text:
#include "cairoint.h"

#if CAIRO_HAS_XLIB_XCB_FUNCTIONS

#include "cairo-xlib.h"
#include "cairo-xcb.h"

#include "cairo-xcb-private.h"
#include "cairo-xlib-xrender-private.h"

#include "cairo-default-context-private.h"
#include "cairo-list-inline.h"
#include "cairo-image-surface-private.h"
#include "cairo-surface-backend-private.h"

#include <X11/Xlib-xcb.h>
#include <X11/Xlibint.h>	/* For XESetCloseDisplay */

struct cairo_xlib_xcb_display_t {
    cairo_device_t  base;

    Display        *dpy;
    cairo_device_t *xcb_device;
    XExtCodes      *codes;

    cairo_list_t    link;
};
typedef struct cairo_xlib_xcb_display_t cairo_xlib_xcb_display_t;

/* List of all #cairo_xlib_xcb_display_t alive,
 * protected by _cairo_xlib_display_mutex */
static cairo_list_t displays;

static cairo_surface_t *
_cairo_xlib_xcb_surface_create (void *dpy,
				void *scr,
				void *visual,
				void *format,
				cairo_surface_t *xcb);

static cairo_surface_t *
_cairo_xlib_xcb_surface_create_similar (void			*abstract_other,
					cairo_content_t		 content,
					int			 width,
					int			 height)
{
    cairo_xlib_xcb_surface_t *other = abstract_other;
    cairo_surface_t *xcb;

    xcb = other->xcb->base.backend->create_similar (other->xcb, content, width, height);
    if (unlikely (xcb == NULL || xcb->status))
	return xcb;

    return _cairo_xlib_xcb_surface_create (other->display, other->screen, NULL, NULL, xcb);
}

static cairo_status_t
_cairo_xlib_xcb_surface_finish (void *abstract_surface)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    cairo_status_t status;

    cairo_surface_finish (&surface->xcb->base);
    status = surface->xcb->base.status;
    cairo_surface_destroy (&surface->xcb->base);
    surface->xcb = NULL;

    return status;
}

static cairo_surface_t *
_cairo_xlib_xcb_surface_create_similar_image (void			*abstract_other,
					      cairo_format_t		 format,
					      int			 width,
					      int			 height)
{
    cairo_xlib_xcb_surface_t *surface = abstract_other;
    return cairo_surface_create_similar_image (&surface->xcb->base, format, width, height);
}

static cairo_image_surface_t *
_cairo_xlib_xcb_surface_map_to_image (void *abstract_surface,
				      const cairo_rectangle_int_t *extents)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    return _cairo_surface_map_to_image (&surface->xcb->base, extents);
}

static cairo_int_status_t
_cairo_xlib_xcb_surface_unmap (void *abstract_surface,
			       cairo_image_surface_t *image)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    return _cairo_surface_unmap_image (&surface->xcb->base, image);
}

static cairo_surface_t *
_cairo_xlib_xcb_surface_source (void *abstract_surface,
				cairo_rectangle_int_t *extents)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    return _cairo_surface_get_source (&surface->xcb->base, extents);
}

static cairo_status_t
_cairo_xlib_xcb_surface_acquire_source_image (void *abstract_surface,
					      cairo_image_surface_t **image_out,
					      void **image_extra)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    return _cairo_surface_acquire_source_image (&surface->xcb->base,
						image_out, image_extra);
}

static void
_cairo_xlib_xcb_surface_release_source_image (void *abstract_surface,
					      cairo_image_surface_t *image_out,
					      void *image_extra)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    _cairo_surface_release_source_image (&surface->xcb->base, image_out, image_extra);
}

static cairo_bool_t
_cairo_xlib_xcb_surface_get_extents (void *abstract_surface,
				     cairo_rectangle_int_t *extents)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    return _cairo_surface_get_extents (&surface->xcb->base, extents);
}

static void
_cairo_xlib_xcb_surface_get_font_options (void *abstract_surface,
					  cairo_font_options_t *options)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    cairo_surface_get_font_options (&surface->xcb->base, options);
}

static cairo_int_status_t
_cairo_xlib_xcb_surface_paint (void			*abstract_surface,
			       cairo_operator_t		 op,
			       const cairo_pattern_t	*source,
			       const cairo_clip_t	*clip)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    return _cairo_surface_paint (&surface->xcb->base, op, source, clip);
}

static cairo_int_status_t
_cairo_xlib_xcb_surface_mask (void			*abstract_surface,
			      cairo_operator_t		 op,
			      const cairo_pattern_t	*source,
			      const cairo_pattern_t	*mask,
			      const cairo_clip_t	*clip)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    return _cairo_surface_mask (&surface->xcb->base, op, source, mask, clip);
}

static cairo_int_status_t
_cairo_xlib_xcb_surface_stroke (void				*abstract_surface,
				cairo_operator_t		 op,
				const cairo_pattern_t		*source,
				const cairo_path_fixed_t	*path,
				const cairo_stroke_style_t	*style,
				const cairo_matrix_t		*ctm,
				const cairo_matrix_t		*ctm_inverse,
				double				 tolerance,
				cairo_antialias_t		 antialias,
				const cairo_clip_t		*clip)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    return _cairo_surface_stroke (&surface->xcb->base,
				  op, source, path, style, ctm, ctm_inverse,
				  tolerance, antialias, clip);
}

static cairo_int_status_t
_cairo_xlib_xcb_surface_fill (void			*abstract_surface,
			      cairo_operator_t		 op,
			      const cairo_pattern_t	*source,
			      const cairo_path_fixed_t	*path,
			      cairo_fill_rule_t		 fill_rule,
			      double			 tolerance,
			      cairo_antialias_t		 antialias,
			      const cairo_clip_t	*clip)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    return _cairo_surface_fill (&surface->xcb->base,
				op, source, path,
				fill_rule, tolerance,
				antialias, clip);
}

static cairo_int_status_t
_cairo_xlib_xcb_surface_glyphs (void			*abstract_surface,
				cairo_operator_t	 op,
				const cairo_pattern_t	*source,
				cairo_glyph_t		*glyphs,
				int			 num_glyphs,
				cairo_scaled_font_t	*scaled_font,
				const cairo_clip_t	*clip)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    return _cairo_surface_show_text_glyphs (&surface->xcb->base, op, source,
					    NULL, 0,
					    glyphs, num_glyphs,
					    NULL, 0, 0,
					    scaled_font, clip);
}

static cairo_status_t
_cairo_xlib_xcb_surface_flush (void *abstract_surface, unsigned flags)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    /* We have to call cairo_surface_flush() to make sure snapshots are detached */
    return _cairo_surface_flush (&surface->xcb->base, flags);
}

static cairo_status_t
_cairo_xlib_xcb_surface_mark_dirty (void *abstract_surface,
				    int x, int y,
				    int width, int height)
{
    cairo_xlib_xcb_surface_t *surface = abstract_surface;
    cairo_surface_mark_dirty_rectangle (&surface->xcb->base, x, y, width, height);
    return cairo_surface_status (&surface->xcb->base);
}

static const cairo_surface_backend_t _cairo_xlib_xcb_surface_backend = {
    CAIRO_SURFACE_TYPE_XLIB,
    _cairo_xlib_xcb_surface_finish,

    _cairo_default_context_create, /* XXX */

    _cairo_xlib_xcb_surface_create_similar,
    _cairo_xlib_xcb_surface_create_similar_image,
    _cairo_xlib_xcb_surface_map_to_image,
    _cairo_xlib_xcb_surface_unmap,

    _cairo_xlib_xcb_surface_source,
    _cairo_xlib_xcb_surface_acquire_source_image,
    _cairo_xlib_xcb_surface_release_source_image,
    NULL, /* snapshot */

    NULL, /* copy_page */
    NULL, /* show_page */

    _cairo_xlib_xcb_surface_get_extents,
    _cairo_xlib_xcb_surface_get_font_options,

    _cairo_xlib_xcb_surface_flush,
    _cairo_xlib_xcb_surface_mark_dirty,

    _cairo_xlib_xcb_surface_paint,
    _cairo_xlib_xcb_surface_mask,
    _cairo_xlib_xcb_surface_stroke,
    _cairo_xlib_xcb_surface_fill,
    NULL, /* fill_stroke */
    _cairo_xlib_xcb_surface_glyphs,
};

static void
_cairo_xlib_xcb_display_finish (void *abstract_display)
{
    cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) abstract_display;

    CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
    cairo_list_del (&display->link);
    CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);

    cairo_device_destroy (display->xcb_device);
    display->xcb_device = NULL;

    XESetCloseDisplay (display->dpy, display->codes->extension, NULL);
    /* Drop the reference from _cairo_xlib_xcb_device_create */
    cairo_device_destroy (&display->base);
}

static int
_cairo_xlib_xcb_close_display(Display *dpy, XExtCodes *codes)
{
    cairo_xlib_xcb_display_t *display;

    CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
    cairo_list_foreach_entry (display,
			      cairo_xlib_xcb_display_t,
			      &displays,
			      link)
    {
	if (display->dpy == dpy)
	{
	    /* _cairo_xlib_xcb_display_finish will lock the mutex again
	     * -> deadlock (This mutex isn't recursive) */
	    cairo_device_reference (&display->base);
	    CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);

	    /* Make sure the xcb and xlib-xcb devices are finished */
	    cairo_device_finish (display->xcb_device);
	    cairo_device_finish (&display->base);

	    cairo_device_destroy (&display->base);
	    return 0;
	}
    }
    CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);

    return 0;
}

static const cairo_device_backend_t _cairo_xlib_xcb_device_backend = {
    CAIRO_DEVICE_TYPE_XLIB,

    NULL,
    NULL,

    NULL, /* flush */
    _cairo_xlib_xcb_display_finish,
    free, /* destroy */
};

static cairo_device_t *
_cairo_xlib_xcb_device_create (Display *dpy, cairo_device_t *xcb_device)
{
    cairo_xlib_xcb_display_t *display = NULL;
    cairo_device_t *device;

    if (xcb_device == NULL)
	return NULL;

    CAIRO_MUTEX_INITIALIZE ();

    CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
    if (displays.next == NULL) {
	cairo_list_init (&displays);
    }

    cairo_list_foreach_entry (display,
			      cairo_xlib_xcb_display_t,
			      &displays,
			      link)
    {
	if (display->dpy == dpy) {
	    /* Maintain MRU order. */
	    if (displays.next != &display->link)
		cairo_list_move (&display->link, &displays);

	    /* Grab a reference for our caller */
	    device = cairo_device_reference (&display->base);
	    assert (display->xcb_device == xcb_device);
	    goto unlock;
	}
    }

    display = malloc (sizeof (cairo_xlib_xcb_display_t));
    if (unlikely (display == NULL)) {
	device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
	goto unlock;
    }

    display->codes = XAddExtension (dpy);
    if (unlikely (display->codes == NULL)) {
	device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
	free (display);
	goto unlock;
    }

    _cairo_device_init (&display->base, &_cairo_xlib_xcb_device_backend);

    XESetCloseDisplay (dpy, display->codes->extension, _cairo_xlib_xcb_close_display);
    /* Add a reference for _cairo_xlib_xcb_display_finish. This basically means
     * that the device's reference count never drops to zero
     * as long as our Display* is alive. We need this because there is no
     * "XDelExtension" to undo XAddExtension and having lots of registered
     * extensions slows down libX11. */
    cairo_device_reference (&display->base);

    display->dpy = dpy;
    display->xcb_device = cairo_device_reference(xcb_device);

    cairo_list_add (&display->link, &displays);
    device = &display->base;

unlock:
    CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);

    return device;
}

static cairo_surface_t *
_cairo_xlib_xcb_surface_create (void *dpy,
				void *scr,
				void *visual,
				void *format,
				cairo_surface_t *xcb)
{
    cairo_xlib_xcb_surface_t *surface;

    if (unlikely (xcb->status))
	return xcb;

    surface = malloc (sizeof (*surface));
    if (unlikely (surface == NULL)) {
	cairo_surface_destroy (xcb);
	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
    }

    _cairo_surface_init (&surface->base,
			 &_cairo_xlib_xcb_surface_backend,
			 _cairo_xlib_xcb_device_create (dpy, xcb->device),
			 xcb->content);

    /* _cairo_surface_init() got another reference to the device, drop ours */
    cairo_device_destroy (surface->base.device);

    surface->display = dpy;
    surface->screen = scr;
    surface->visual = visual;
    surface->format = format;
    surface->xcb = (cairo_xcb_surface_t *) xcb;

    return &surface->base;
}

static Screen *
_cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
{
    int s, d, v;

    for (s = 0; s < ScreenCount (dpy); s++) {
	Screen *screen;

	screen = ScreenOfDisplay (dpy, s);
	if (visual == DefaultVisualOfScreen (screen))
	    return screen;

	for (d = 0; d < screen->ndepths; d++) {
	    Depth  *depth;

	    depth = &screen->depths[d];
	    for (v = 0; v < depth->nvisuals; v++)
		if (visual == &depth->visuals[v])
		    return screen;
	}
    }

    return NULL;
}

cairo_surface_t *
cairo_xlib_surface_create (Display     *dpy,
			   Drawable	drawable,
			   Visual      *visual,
			   int		width,
			   int		height)
{
    Screen *scr;
    xcb_visualtype_t xcb_visual;

    scr = _cairo_xlib_screen_from_visual (dpy, visual);
    if (scr == NULL)
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));

    xcb_visual.visual_id = visual->visualid;
#if defined(__cplusplus) || defined(c_plusplus)
    xcb_visual._class = visual->c_class;
#else
    xcb_visual._class = visual->class;
#endif
    xcb_visual.bits_per_rgb_value = visual->bits_per_rgb;
    xcb_visual.colormap_entries = visual->map_entries;
    xcb_visual.red_mask = visual->red_mask;
    xcb_visual.green_mask = visual->green_mask;
    xcb_visual.blue_mask = visual->blue_mask;

    return _cairo_xlib_xcb_surface_create (dpy, scr, visual, NULL,
					   cairo_xcb_surface_create (XGetXCBConnection (dpy),
								     drawable,
								     &xcb_visual,
								     width, height));
}

cairo_surface_t *
cairo_xlib_surface_create_for_bitmap (Display  *dpy,
				      Pixmap	bitmap,
				      Screen   *scr,
				      int	width,
				      int	height)
{
    return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, NULL,
					   cairo_xcb_surface_create_for_bitmap (XGetXCBConnection (dpy),
										(xcb_screen_t *) scr,
										bitmap,
										width, height));
}

#if CAIRO_HAS_XLIB_XRENDER_SURFACE
static xcb_screen_t *
_cairo_xcb_screen_from_root (xcb_connection_t *connection,
			     xcb_window_t id)
{
    xcb_screen_iterator_t s;

    s = xcb_setup_roots_iterator (xcb_get_setup (connection));
    for (; s.rem; xcb_screen_next (&s)) {
	if (s.data->root == id)
	    return s.data;
    }

    return NULL;
}
cairo_surface_t *
cairo_xlib_surface_create_with_xrender_format (Display		    *dpy,
					       Drawable		    drawable,
					       Screen		    *scr,
					       XRenderPictFormat    *format,
					       int		    width,
					       int		    height)
{
    xcb_render_pictforminfo_t xcb_format;
    xcb_connection_t *connection;
    xcb_screen_t *screen;

    xcb_format.id = format->id;
    xcb_format.type = format->type;
    xcb_format.depth = format->depth;
    xcb_format.direct.red_shift = format->direct.red;
    xcb_format.direct.red_mask = format->direct.redMask;
    xcb_format.direct.green_shift = format->direct.green;
    xcb_format.direct.green_mask = format->direct.greenMask;
    xcb_format.direct.blue_shift = format->direct.blue;
    xcb_format.direct.blue_mask = format->direct.blueMask;
    xcb_format.direct.alpha_shift = format->direct.alpha;
    xcb_format.direct.alpha_mask = format->direct.alphaMask;
    xcb_format.colormap = format->colormap;

    connection = XGetXCBConnection (dpy);
    screen = _cairo_xcb_screen_from_root (connection, (xcb_window_t) scr->root);

    return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, format,
					   cairo_xcb_surface_create_with_xrender_format (connection, screen,
											 drawable,
											 &xcb_format,
											 width, height));
}

XRenderPictFormat *
cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface)
{
    cairo_xlib_xcb_surface_t *xlib_surface = (cairo_xlib_xcb_surface_t *) surface;

    /* Throw an error for a non-xlib surface */
    if (surface->type != CAIRO_SURFACE_TYPE_XLIB) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return NULL;
    }

    return xlib_surface->format;
}
#endif

void
cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
			     int              width,
			     int              height)
{
    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
    cairo_status_t status;

    if (unlikely (abstract_surface->status))
	return;
    if (unlikely (abstract_surface->finished)) {
	status = _cairo_surface_set_error (abstract_surface,
		                           _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
	return;
    }

    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
	status = _cairo_surface_set_error (abstract_surface,
		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return;
    }

    cairo_xcb_surface_set_size (&surface->xcb->base, width, height);
    if (unlikely (surface->xcb->base.status)) {
	status = _cairo_surface_set_error (abstract_surface,
		                           _cairo_error (surface->xcb->base.status));
    }
}

void
cairo_xlib_surface_set_drawable (cairo_surface_t   *abstract_surface,
				 Drawable	    drawable,
				 int		    width,
				 int		    height)
{
    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *)abstract_surface;
    cairo_status_t status;

    if (unlikely (abstract_surface->status))
	return;
    if (unlikely (abstract_surface->finished)) {
	status = _cairo_surface_set_error (abstract_surface,
		                           _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
	return;
    }

    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
	status = _cairo_surface_set_error (abstract_surface,
		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return;
    }

    cairo_xcb_surface_set_drawable (&surface->xcb->base, drawable, width, height);
    if (unlikely (surface->xcb->base.status)) {
	status = _cairo_surface_set_error (abstract_surface,
		                           _cairo_error (surface->xcb->base.status));
    }
}

Display *
cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
{
    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;

    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return NULL;
    }

    return surface->display;
}

Drawable
cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
{
    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;

    if (unlikely (abstract_surface->finished)) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
	return 0;
    }
    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return 0;
    }
    /* This can happen when e.g. create_similar falls back to an image surface
     * because we don't have the RENDER extension. */
    if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return 0;
    }

    return surface->xcb->drawable;
}

Screen *
cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
{
    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;

    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return NULL;
    }

    return surface->screen;
}

Visual *
cairo_xlib_surface_get_visual (cairo_surface_t *abstract_surface)
{
    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;

    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return NULL;
    }

    return surface->visual;
}

int
cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
{
    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;

    if (unlikely (abstract_surface->finished)) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
	return 0;
    }
    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return 0;
    }
    /* This can happen when e.g. create_similar falls back to an image surface
     * because we don't have the RENDER extension. */
    if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return 0;
    }

    return surface->xcb->depth;
}

int
cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
{
    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;

    if (unlikely (abstract_surface->finished)) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
	return 0;
    }
    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return 0;
    }
    /* This can happen when e.g. create_similar falls back to an image surface
     * because we don't have the RENDER extension. */
    if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return 0;
    }

    return surface->xcb->width;
}

int
cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
{
    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;

    if (unlikely (abstract_surface->finished)) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
	return 0;
    }
    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return 0;
    }
    /* This can happen when e.g. create_similar falls back to an image surface
     * because we don't have the RENDER extension. */
    if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return 0;
    }

    return surface->xcb->height;
}

void
cairo_xlib_device_debug_cap_xrender_version (cairo_device_t *device,
					     int major, int minor)
{
    cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;

    if (device == NULL || device->status)
	return;

    if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB)
	return;

    cairo_xcb_device_debug_cap_xrender_version (display->xcb_device,
						major, minor);
}

void
cairo_xlib_device_debug_set_precision (cairo_device_t *device,
				       int precision)
{
    cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;

    if (device == NULL || device->status)
	return;
    if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
	cairo_status_t status;

	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
	(void) status;
	return;
    }

    cairo_xcb_device_debug_set_precision (display->xcb_device, precision);
}

int
cairo_xlib_device_debug_get_precision (cairo_device_t *device)
{
    cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;

    if (device == NULL || device->status)
	return -1;
    if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
	cairo_status_t status;

	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
	(void) status;
	return -1;
    }

    return cairo_xcb_device_debug_get_precision (display->xcb_device);
}

#endif /* CAIRO_HAS_XLIB_XCB_FUNCTIONS */


text:
package com.asakusafw.lang.compiler.planning.basic;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import com.asakusafw.lang.compiler.common.util.EnumUtil;
import com.asakusafw.lang.compiler.model.graph.MarkerOperator;
import com.asakusafw.lang.compiler.model.graph.Operator;
import com.asakusafw.lang.compiler.model.graph.OperatorConstraint;
import com.asakusafw.lang.compiler.model.graph.OperatorInput;
import com.asakusafw.lang.compiler.model.graph.OperatorOutput;
import com.asakusafw.lang.compiler.model.graph.Operators;
import com.asakusafw.lang.compiler.planning.PlanMarker;
import com.asakusafw.lang.compiler.planning.PlanMarkers;
import com.asakusafw.lang.compiler.planning.SubPlan;
import com.asakusafw.lang.compiler.planning.basic.BasicSubPlan.BasicInput;

/**
 * A group of isomorphic operators.
 */
final class OperatorGroup {

    private final BasicSubPlan owner;

    private final Set<Operator> operators;

    private final BitSet broadcastInputIndices;

    private final Set<Attribute> attributes;

    OperatorGroup(
            BasicSubPlan owner, Set<Operator> operators,
            BitSet broadcastInputIndices, Set<Attribute> attributes) {
        this.owner = owner;
        this.operators = new LinkedHashSet<>(operators);
        this.broadcastInputIndices = (BitSet) broadcastInputIndices.clone();
        this.attributes = EnumUtil.freeze(attributes);
    }

    public static Set<Attribute> getAttributes(SubPlan owner, Operator operator) {
        Set<Attribute> results = EnumSet.noneOf(Attribute.class);
        if (isExtractKind(owner, operator)) {
            results.add(Attribute.EXTRACT_KIND);
        }
        if (operator.getConstraints().contains(OperatorConstraint.GENERATOR)) {
            results.add(Attribute.GENERATOR);
        }
        if (operator.getConstraints().contains(OperatorConstraint.AT_LEAST_ONCE)) {
            results.add(Attribute.CONSUMER);
        }
        if (owner.findInput(operator) != null) {
            results.add(Attribute.INPUT);
        }
        if (owner.findOutput(operator) != null) {
            results.add(Attribute.OUTPUT);
        }
        PlanMarker marker = PlanMarkers.get(operator);
        if (marker != null) {
            switch (marker) {
            case BEGIN:
                results.add(Attribute.BEGIN);
                break;
            case END:
                results.add(Attribute.END);
                break;
            case CHECKPOINT:
                results.add(Attribute.CHECKPOINT);
                break;
            case GATHER:
                results.add(Attribute.GATHER);
                break;
            case BROADCAST:
                results.add(Attribute.BROADCAST);
                break;
            default:
                // ignore unknown markers
                break;
            }
        }
        return results;
    }

    private static boolean isExtractKind(SubPlan owner, Operator operator) {
        // for safety, we assumes that GATHER (input) is not extract kind
        if (PlanMarkers.get(operator) == PlanMarker.GATHER
                && owner.findInput(operator) != null) {
            return false;
        }
        // operator following GATHER is not extract kind
        for (Operator pred : Operators.getPredecessors(operator)) {
            if (PlanMarkers.get(pred) == PlanMarker.GATHER) {
                return false;
            }
        }
        return true;
    }

    public boolean isEmpty() {
        return operators.isEmpty();
    }

    public boolean has(Attribute attribute) {
        return attributes.contains(attribute);
    }

    public void remove(Operator operator) {
        if (operators.remove(operator)) {
            owner.removeOperator(operator);
        }
    }

    public boolean applyRedundantOutputElimination() {
        return applyCombination((base, target) -> applyRedundantOutputElimination(base, target));
    }

    boolean applyRedundantOutputElimination(Operator base, Operator target) {
        // a +-- $ --- b
        //    \- $ --- c
        // >>>
        // a --- $ +-- b
        //    \- $  \- c
        if (hasSameInputs(base, target) == false) {
            return false;
        }
        if (attributes.contains(Attribute.OUTPUT)) {
            BasicSubPlan.BasicOutput baseOut = owner.findOutput(base);
            BasicSubPlan.BasicOutput targetOut = owner.findOutput(target);
            assert baseOut != null;
            assert targetOut != null;
            Set<BasicInput> downstreams = targetOut.getOpposites();
            if (downstreams.isEmpty()) {
                return false;
            }
            for (BasicSubPlan.BasicInput downstream : downstreams) {
                baseOut.connect(downstream);
            }
            targetOut.disconnectAll();
            return true;
        } else {
            if (Operators.hasSuccessors(target) == false) {
                return false;
            }
            List<OperatorOutput> sources = target.getOutputs();
            List<OperatorOutput> destinations = base.getOutputs();
            assert sources.size() == destinations.size();
            for (int i = 0, n = sources.size(); i < n; i++) {
                OperatorOutput source = sources.get(i);
                OperatorOutput destination = destinations.get(i);
                assert source.getDataType().equals(destination.getDataType());
                Collection<OperatorInput> downstreams = source.getOpposites();
                if (downstreams.isEmpty() == false) {
                    Operators.connectAll(destination, downstreams);
                    source.disconnectAll();
                }
            }
            return true;
        }
    }

    public boolean applyUnionPushDown() {
        if (attributes.contains(Attribute.EXTRACT_KIND) == false
                || attributes.contains(Attribute.GENERATOR)) {
            return false;
        }
        return applyCombination((base, target) -> applyUnionPushDown(base, target));
    }

    boolean applyUnionPushDown(Operator base, Operator target) {
        if (hasSameOutputs(base, target) == false || hasSameBroadcastInputs(base, target) == false) {
            return false;
        }
        // a --- $ --+ c
        // b --- $ -/
        // >>>
        // a --+ $ --+ c
        // b -/  $ -/
        if (attributes.contains(Attribute.INPUT)) {
            BasicSubPlan.BasicInput baseIn = owner.findInput(base);
            BasicSubPlan.BasicInput targetIn = owner.findInput(target);
            assert baseIn != null;
            assert targetIn != null;
            Set<BasicSubPlan.BasicOutput> upstreams = targetIn.getOpposites();
            if (upstreams.isEmpty()) {
                return false;
            }
            for (BasicSubPlan.BasicOutput upstream : upstreams) {
                baseIn.connect(upstream);
            }
            targetIn.disconnectAll();
            return true;
        } else {
            if (Operators.hasPredecessors(target) == false) {
                return false;
            }
            List<OperatorInput> sources = target.getInputs();
            List<OperatorInput> destinations = base.getInputs();
            assert sources.size() == destinations.size();
            for (int i = 0, n = sources.size(); i < n; i++) {
                OperatorInput source = sources.get(i);
                if (broadcastInputIndices.get(i) == false) {
                    OperatorInput destination = destinations.get(i);
                    assert source.getDataType().equals(destination.getDataType());
                    Collection<OperatorOutput> upstreams = source.getOpposites();
                    Operators.connectAll(upstreams, destination);
                }
                source.disconnectAll();
            }
            return true;
        }
    }

    private boolean applyCombination(Applier applier) {
        if (operators.size() <= 1) {
            return false;
        }
        boolean changed = false;
        BitSet applied = new BitSet();
        Operator[] ops = operators.toArray(new Operator[operators.size()]);
        for (int baseIndex = 0; baseIndex < ops.length - 1; baseIndex++) {
            if (applied.get(baseIndex)) {
                continue;
            }
            Operator base = ops[baseIndex];
            for (int targetIndex = baseIndex + 1; targetIndex < ops.length; targetIndex++) {
                if (applied.get(targetIndex)) {
                    continue;
                }
                Operator target = ops[targetIndex];
                if (applier.apply(base, target)) {
                    applied.set(targetIndex);
                    changed = true;
                }
            }
        }
        return changed;
    }

    public boolean applyTrivialOutputElimination() {
        if (operators.isEmpty()) {
            return false;
        }
        // NOTE this never change sub-plan inputs/outputs
        // non-extract/generator/consumer is checked later
        if (attributes.contains(Attribute.INPUT)
                || attributes.contains(Attribute.OUTPUT)) {
            return false;
        }
        boolean changed = false;
        for (Operator operator : operators) {
            changed |= applyTrivialOutputElimination(operator);
        }
        return changed;
    }

    private boolean applyTrivialOutputElimination(Operator operator) {
        if (Operators.hasSuccessors(operator) == false) {
            return false;
        }
        // () ===> a --- $ --- b
        // >>>
        // () ===> a +-------- b
        //            \- $
        boolean changed = false;

        // shrink trivial upstream operators
        // but here we keep at least one upstream per port
        List<OperatorInput> inputs = operator.getInputs();
        for (int i = 0, n = inputs.size(); i < n; i++) {
            changed |= shrinkTrivialUpstreams(inputs.get(i));
        }

        // never remove non-extract/generator/consumer operators
        if (attributes.contains(Attribute.EXTRACT_KIND) == false
                || attributes.contains(Attribute.GENERATOR)
                || attributes.contains(Attribute.CONSUMER)) {
            return changed;
        }

        // try remove operator itself
        MarkerOperator primary = null;
        for (int i = 0, n = inputs.size(); i < n; i++) {
            // ignores broadcast inputs
            if (broadcastInputIndices.get(i)) {
                continue;
            }
            OperatorInput input = inputs.get(i);
            for (OperatorOutput upstream : input.getOpposites()) {
                SubPlan.Input in = owner.findInput(upstream.getOwner());
                if (in != null && in.getOpposites().isEmpty()) {
                    if (primary == null) {
                        primary = in.getOperator();
                    }
                } else {
                    // operator is not empty
                    return changed;
                }
            }
        }

        if (primary != null) {
            // try bypass upstream and downstream
            Set<OperatorInput> downstreams = new HashSet<>();
            for (OperatorOutput output : operator.getOutputs()) {
                downstreams.addAll(output.getOpposites());
            }
            Operators.connectAll(primary.getOutput(), downstreams);
        }
        operator.disconnectAll();
        return true;
    }

    private boolean shrinkTrivialUpstreams(OperatorInput port) {
        Collection<OperatorOutput> upstreams = port.getOpposites();
        if (upstreams.isEmpty()) {
            return false;
        }
        List<MarkerOperator> trivials = new ArrayList<>(upstreams.size());
        boolean sawNonTrivial = false;
        for (OperatorOutput upstream : upstreams) {
            SubPlan.Input in = owner.findInput(upstream.getOwner());
            if (in != null && in.getOpposites().isEmpty()) {
                trivials.add(in.getOperator());
            } else {
                sawNonTrivial = true;
            }
        }
        if (trivials.isEmpty()) {
            return false;
        }
        boolean changed = false;
        if (sawNonTrivial) {
            for (MarkerOperator trivial : trivials) {
                assert port.isConnected(trivial.getOutput());
                port.disconnect(trivial.getOutput());
                changed = true;
            }
        } else {
            long minId = trivials.get(0).getSerialNumber();
            for (int i = 1, n = trivials.size(); i < n; i++) {
                minId = Math.min(minId, trivials.get(i).getSerialNumber());
            }
            for (MarkerOperator trivial : trivials) {
                // disconnect from operator expect which has minimum serial number (for stable operations)
                if (trivial.getSerialNumber() == minId) {
                    continue;
                }
                port.disconnect(trivial.getOutput());
                changed = true;
            }
        }
        return changed;
    }

    public boolean applyDuplicateCheckpointElimination() {
        if (operators.isEmpty()) {
            return false;
        }
        if (attributes.contains(Attribute.INPUT) == false
                || attributes.contains(Attribute.CHECKPOINT) == false) {
            return false;
        }
        boolean changed = false;
        for (Operator operator : operators) {
            changed |= applyDuplicateCheckpointElimination(operator);
        }
        return changed;
    }

    private boolean applyDuplicateCheckpointElimination(Operator operator) {
        if (Operators.hasSuccessors(operator) == false) {
            return false;
        }
        // c0 ===> $ +--------+ c1 ===> c1
        //            \- o0 -/
        // >>>
        // c0 +======================+> c1
        //     \=> $ --- o0 --- c1 =/
        boolean changed = false;
        BasicSubPlan.BasicInput input = owner.findInput(operator);
        assert input != null;
        Set<BasicSubPlan.BasicOutput> upstreams = input.getOpposites();
        OperatorOutput port = input.getOperator().getOutput();
        for (OperatorInput opposite : port.getOpposites()) {
            Operator succ = opposite.getOwner();
            BasicSubPlan.BasicOutput output = owner.findOutput(succ);
            if (output == null) {
                continue;
            }
            if (PlanMarkers.get(succ) != PlanMarker.CHECKPOINT) {
                continue;
            }
            Set<BasicSubPlan.BasicInput> downstreams = output.getOpposites();
            for (BasicSubPlan.BasicOutput upstream : upstreams) {
                for (BasicSubPlan.BasicInput downstream : downstreams) {
                    assert upstream.isConnected(downstream) == false;
                    upstream.connect(downstream);
                }
            }
            port.disconnect(opposite);
            changed = true;
        }
        return changed;
    }

    // has-same-inputs and is-isomorphic => has-equivalent-outputs
    private boolean hasSameInputs(Operator a, Operator b) {
        assert operators.contains(a);
        assert operators.contains(b);
        if (attributes.contains(Attribute.INPUT)) {
            SubPlan.Input aPort = owner.findInput(a);
            SubPlan.Input bPort = owner.findInput(b);
            assert aPort != null;
            assert bPort != null;
            return aPort.getOpposites().equals(bPort.getOpposites());
        } else {
            List<OperatorInput> aPorts = a.getInputs();
            List<OperatorInput> bPorts = b.getInputs();
            assert aPorts.size() == bPorts.size();
            for (int i = 0, n = aPorts.size(); i < n; i++) {
                OperatorInput aPort = aPorts.get(i);
                OperatorInput bPort = bPorts.get(i);
                if (aPort.hasSameOpposites(bPort) == false) {
                    return false;
                }
            }
            return true;
        }
    }

    private boolean hasSameBroadcastInputs(Operator a, Operator b) {
        assert operators.contains(a);
        assert operators.contains(b);
        BitSet indices = broadcastInputIndices;
        if (indices.isEmpty()) {
            return true;
        }
        // sub-plan inputs must not have any broadcast inputs
        assert attributes.contains(Attribute.INPUT) == false;
        List<OperatorInput> aPorts = a.getInputs();
        List<OperatorInput> bPorts = b.getInputs();
        assert aPorts.size() == bPorts.size();
        for (int i = indices.nextSetBit(0), n = aPorts.size(); i >= 0 && i < n; i = indices.nextSetBit(i + 1)) {
            OperatorInput aPort = aPorts.get(i);
            OperatorInput bPort = bPorts.get(i);
            if (aPort.hasSameOpposites(bPort) == false) {
                return false;
            }
        }
        return true;
    }

    private boolean hasSameOutputs(Operator a, Operator b) {
        assert operators.contains(a);
        assert operators.contains(b);
        if (attributes.contains(Attribute.OUTPUT)) {
            SubPlan.Output aPort = owner.findOutput(a);
            SubPlan.Output bPort = owner.findOutput(b);
            assert aPort != null;
            assert bPort != null;
            return aPort.getOpposites().equals(bPort.getOpposites());
        } else {
            List<OperatorOutput> aPorts = a.getOutputs();
            List<OperatorOutput> bPorts = b.getOutputs();
            assert aPorts.size() == bPorts.size();
            for (int i = 0, n = aPorts.size(); i < n; i++) {
                OperatorOutput aPort = aPorts.get(i);
                OperatorOutput bPort = bPorts.get(i);
                if (aPort.hasSameOpposites(bPort) == false) {
                    return false;
                }
            }
            return true;
        }
    }

    @Override
    public String toString() {
        if (operators.isEmpty()) {
            return "OperatorGroup(+0)"; //$NON-NLS-1$
        } else {
            Operator first = operators.iterator().next();
            return MessageFormat.format(
                    "OperatorGroup{2}({0}+{1})", //$NON-NLS-1$
                    first,
                    operators.size() - 1,
                    attributes);
        }
    }

    @FunctionalInterface
    private interface Applier {

        boolean apply(Operator base, Operator target);
    }

    public static final class GroupInfo {

        final Object id;

        final BitSet broadcastInputIndices;

        final Set<Attribute> attributes;

        GroupInfo(Object id, BitSet broadcastInputIndices, Set<Attribute> attributes) {
            this.id = id;
            this.broadcastInputIndices = broadcastInputIndices;
            this.attributes = attributes;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + Objects.hashCode(id);
            result = prime * result + broadcastInputIndices.hashCode();
            result = prime * result + attributes.hashCode();
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            GroupInfo other = (GroupInfo) obj;
            if (!Objects.equals(id, other.id)) {
                return false;
            }
            if (!broadcastInputIndices.equals(other.broadcastInputIndices)) {
                return false;
            }
            if (!attributes.equals(other.attributes)) {
                return false;
            }
            return true;
        }

        @Override
        public String toString() {
            return MessageFormat.format("Group({0})", id); //$NON-NLS-1$
        }
    }

    public enum Attribute {

        /**
         * Is extract kind.
         */
        EXTRACT_KIND,

        /**
         * Is sub-plan inputs.
         */
        INPUT,

        /**
         * Is sub-plan outputs.
         */
        OUTPUT,

        /**
         * Is generator.
         */
        GENERATOR,

        /**
         * Is consumer.
         */
        CONSUMER,

        /**
         * Is BEGIN plan markers.
         */
        BEGIN,

        /**
         * Is END plan markers.
         */
        END,

        /**
         * Is CHECKPOINT plan markers.
         */
        CHECKPOINT,

        /**
         * Is GATHER plan markers.
         */
        GATHER,

        /**
         * Is BROADCAST plan markers.
         */
        BROADCAST,
    }
}

redpajama_set_name: RedPajamaGithub


text:
/* ** GENEREATED FILE - DO NOT MODIFY ** */
package com.wilutions.mslib.uccollaborationlib;
import com.wilutions.com.*;

/**
 * IConferenceAccessInformation.
 * IConferenceAccessInformation Interface
 */
@CoInterface(guid="{2F8C3E58-436B-42DB-8924-6C394B37DCA2}")
public interface IConferenceAccessInformation extends IDispatch {
  static boolean __typelib__loaded = __TypeLib.load();
  @DeclDISPID(1610743808)  public String getId() throws ComException;
  @DeclDISPID(1610743809)  public String[] getAutoAttendantNumbers() throws ComException;
  @DeclDISPID(1610743810)  public String getAdmissionKey() throws ComException;
  @DeclDISPID(1610743811)  public String getInternalUrl() throws ComException;
  @DeclDISPID(1610743812)  public String getExternalUrl() throws ComException;
}


text:
package slog_test

import (
	"encoding/json"
	"testing"

	"github.com/spkg/slog"
	"github.com/stretchr/testify/assert"
)

func TestString(t *testing.T) {
	assert := assert.New(t)
	testCases := []struct {
		Level    slog.Level
		Expected string
	}{
		{slog.LevelDebug, "debug"},
		{slog.LevelInfo, "info"},
		{slog.LevelWarning, "warn"},
		{slog.LevelError, "error"},
		{slog.Level(63), "unknown 63"},
	}

	for _, tc := range testCases {
		assert.Equal(tc.Expected, tc.Level.String())
	}
}

func TestMarshalJSON(t *testing.T) {
	assert := assert.New(t)

	s := struct{ Level slog.Level }{slog.LevelError}
	b, err := json.Marshal(&s)
	assert.NoError(err)
	assert.Equal(`{"Level":"error"}`, string(b))

	var s2 struct{ Level slog.Level }
	err = json.Unmarshal(b, &s2)
	assert.NoError(err)
	assert.Equal(s.Level, s2.Level)
}

func TestMarshalText(t *testing.T) {
	assert := assert.New(t)
	testCases := []struct {
		Level    slog.Level
		Expected string
		Valid    []string
		Invalid  []string
	}{
		{Level: slog.LevelDebug, Expected: "debug", Valid: []string{"Debug", "DEBUG"}},
		{Level: slog.LevelInfo, Expected: "info", Valid: []string{"INFO", "information"}, Invalid: []string{"xxxx"}},
		{Level: slog.LevelWarning, Expected: "warn", Valid: []string{"Warning", "WARN"}},
		{Level: slog.LevelError, Expected: "error"},
	}

	for _, tc := range testCases {
		b, err := tc.Level.MarshalText()
		assert.NoError(err)
		assert.Equal(tc.Expected, string(b))

		var level slog.Level
		err = level.UnmarshalText(b)
		assert.NoError(err)
		assert.Equal(tc.Level, level)

		for _, text := range tc.Valid {
			err = level.UnmarshalText([]byte(text))
			assert.NoError(err)
			assert.Equal(tc.Level, level)
		}
		for _, text := range tc.Invalid {
			err = level.UnmarshalText([]byte(text))
			assert.Error(err)
		}
	}
}


text: - Now uses version 0.31 of the rust sdl2 bindings


text:
require 'spec_helper'
require 'cucumber-loggly/cli'

describe CucumberLoggly::CLI do
  before do
    ARGV.stub :shift => '/given/features'
    @pathname = Pathname.new('features').expand_path
    @cmd = "cucumber --require #{@pathname} /given/features"
  end

  context "when successful" do

    it "should set the feature dir to the feature dir within gem" do
      root        = Pathname.new(__FILE__).parent.parent
      feature_dir = root.join('features')
      File.stub :exist? => true
      cli = CucumberLoggly::CLI.new
      cli.instance_variable_get(:@feature_dir).should == feature_dir
    end

    it "should run the command" do
      File.stub :exist? => true
      cli = CucumberLoggly::CLI.new
      cli.should_receive(:system).with(@cmd).and_return true
      cli.start
    end
  end

  context "when unsuccessful" do
    it "should exit 1 if the command does not return true" do
      File.stub :exist? => true
      cli = CucumberLoggly::CLI.new
      cli.should_receive(:system).with(@cmd).and_return false
      lambda { cli.start }.should raise_error SystemExit
    end

    it "should exit if the config file does not exist" do
      File.stub :exist? => false
      cli = CucumberLoggly::CLI.new
      cli.should_receive(:puts)
      lambda { cli.start }.should raise_error SystemExit
    end
  end
end


text:
#ifndef SERF_H
#define SERF_H

/**
 * @file serf.h
 * @brief Main serf header file
 */

#include <apr.h>
#include <apr_errno.h>
#include <apr_allocator.h>
#include <apr_pools.h>
#include <apr_network_io.h>
#include <apr_time.h>
#include <apr_poll.h>
#include <apr_uri.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Forward declare some structures */
typedef struct serf_context_t serf_context_t;

typedef struct serf_bucket_t serf_bucket_t;
typedef struct serf_bucket_type_t serf_bucket_type_t;
typedef struct serf_bucket_alloc_t serf_bucket_alloc_t;

typedef struct serf_connection_t serf_connection_t;
typedef struct serf_listener_t serf_listener_t;
typedef struct serf_incoming_t serf_incoming_t;
typedef struct serf_incoming_request_t serf_incoming_request_t;

typedef struct serf_request_t serf_request_t;

/**
 * @defgroup serf high-level constructs
 * @ingroup serf
 * @{
 */

/**
 * Serf-specific error codes
 */
#define SERF_ERROR_RANGE 100
#define SERF_ERROR_START (APR_OS_START_USERERR + SERF_ERROR_RANGE)

/* This code is for when this is the last response on this connection:
 * i.e. do not send any more requests on this connection or expect
 * any more responses.
 */
#define SERF_ERROR_CLOSING (SERF_ERROR_START + 1)
/* This code is for when the connection terminated before the request
 * could be processed on the other side.
 */
#define SERF_ERROR_REQUEST_LOST (SERF_ERROR_START + 2)
/* This code is for when the connection is blocked - we can not proceed
 * until something happens - generally due to SSL negotiation-like behavior
 * where a write() is blocked until a read() is processed.
 */
#define SERF_ERROR_WAIT_CONN (SERF_ERROR_START + 3)
/* This code is for when something went wrong during deflating compressed
 * data e.g. a CRC error. */
#define SERF_ERROR_DECOMPRESSION_FAILED (SERF_ERROR_START + 4)
/* This code is for when a response received from a http server is not in
 * http-compliant syntax. */
#define SERF_ERROR_BAD_HTTP_RESPONSE (SERF_ERROR_START + 5)
/* The server sent less data than what was announced. */
#define SERF_ERROR_TRUNCATED_HTTP_RESPONSE (SERF_ERROR_START + 6)
/* The proxy server returned an error while setting up the SSL tunnel. */
#define SERF_ERROR_SSLTUNNEL_SETUP_FAILED (SERF_ERROR_START + 7)
/* The server unexpectedly closed the connection prematurely. */
#define SERF_ERROR_ABORTED_CONNECTION (SERF_ERROR_START + 8)

/* SSL certificates related errors */
#define SERF_ERROR_SSL_CERT_FAILED (SERF_ERROR_START + 70)

/* SSL communications related errors */
#define SERF_ERROR_SSL_COMM_FAILED (SERF_ERROR_START + 71)

/* General authentication related errors */
#define SERF_ERROR_AUTHN_FAILED (SERF_ERROR_START + 90)

/* None of the available authn mechanisms for the request are supported */
#define SERF_ERROR_AUTHN_NOT_SUPPORTED (SERF_ERROR_START + 91)

/* Authn was requested by the server but the header lacked some attribute  */
#define SERF_ERROR_AUTHN_MISSING_ATTRIBUTE (SERF_ERROR_START + 92)

/* Authentication handler initialization related errors */
#define SERF_ERROR_AUTHN_INITALIZATION_FAILED (SERF_ERROR_START + 93)

/* Error code reserved for use in the test suite. */
#define SERF_ERROR_ISSUE_IN_TESTSUITE (SERF_ERROR_START + 99)

/* This macro groups errors potentially raised when reading a http response.  */
#define SERF_BAD_RESPONSE_ERROR(status) ((status) \
    && ((SERF_ERROR_DECOMPRESSION_FAILED == (status)) \
        ||(SERF_ERROR_BAD_HTTP_RESPONSE == (status)) \
        ||(SERF_ERROR_TRUNCATED_HTTP_RESPONSE == (status))))

/**
 * Return a string that describes the specified error code.
 *
 * If the error code is not one of the above Serf error codes, then
 * NULL will be returned.
 *
 * Note regarding lifetime: the string is a statically-allocated constant
 */
const char *serf_error_string(apr_status_t errcode);

/**
 * Create a new context for serf operations.
 *
 * A serf context defines a control loop which processes multiple
 * connections simultaneously.
 *
 * The context will be allocated within @a pool.
 */
serf_context_t *serf_context_create(
    apr_pool_t *pool);

/**
 * Callback function. Add a socket to the externally managed poll set.
 *
 * Both @a pfd and @a serf_baton should be used when calling serf_event_trigger
 * later.
 */
typedef apr_status_t (*serf_socket_add_t)(
    void *user_baton,
    apr_pollfd_t *pfd,
    void *serf_baton);

/**
 * Callback function. Remove the socket, identified by both @a pfd and
 * @a serf_baton from the externally managed poll set.
 */
typedef apr_status_t (*serf_socket_remove_t)(
    void *user_baton,
    apr_pollfd_t *pfd,
    void *serf_baton);

/* Create a new context for serf operations.
 *
 * Use this function to make serf not use its internal control loop, but
 * instead rely on an external event loop. Serf will use the @a addf and @a rmf
 * callbacks to notify of any event on a connection. The @a user_baton will be
 * passed through the addf and rmf callbacks.
 *
 * The context will be allocated within @a pool.
 */
serf_context_t *serf_context_create_ex(
    void *user_baton,
    serf_socket_add_t addf,
    serf_socket_remove_t rmf,
    apr_pool_t *pool);

/**
 * Make serf process events on a connection, identified by both @a pfd and
 * @a serf_baton.
 *
 * Any outbound data is delivered, and incoming data is made available to
 * the associated response handlers and their buckets.
 *
 * If any data is processed (incoming or outgoing), then this function will
 * return with APR_SUCCESS.
 */
apr_status_t serf_event_trigger(
    serf_context_t *s,
    void *serf_baton,
    const apr_pollfd_t *pfd);

/** @see serf_context_run should not block at all. */
#define SERF_DURATION_NOBLOCK 0
/** @see serf_context_run should run for (nearly) "forever". */
#define SERF_DURATION_FOREVER 2000000000        /* approx 1^31 */

/**
 * Run the main networking control loop.
 *
 * The set of connections defined by the serf context @a ctx are processed.
 * Any outbound data is delivered, and incoming data is made available to
 * the associated response handlers and their buckets. This function will
 * block on the network for no longer than @a duration microseconds.
 *
 * If any data is processed (incoming or outgoing), then this function will
 * return with APR_SUCCESS. Typically, the caller will just want to call it
 * again to continue processing data.
 *
 * If no activity occurs within the specified timeout duration, then
 * APR_TIMEUP is returned.
 *
 * All temporary allocations will be made in @a pool.
 */
apr_status_t serf_context_run(
    serf_context_t *ctx,
    apr_short_interval_time_t duration,
    apr_pool_t *pool);

apr_status_t serf_context_prerun(
    serf_context_t *ctx);

/**
 * Callback function for progress information. @a progress indicates cumulative
 * number of bytes read or written, for the whole context.
 */
typedef void (*serf_progress_t)(
    void *progress_baton,
    apr_off_t read,
    apr_off_t write);

/**
 * Sets the progress callback function. @a progress_func will be called every
 * time bytes are read of or written on a socket.
 */
void serf_context_set_progress_cb(
    serf_context_t *ctx,
    const serf_progress_t progress_func,
    void *progress_baton);

/** @} */

/**
 * @defgroup serf connections and requests
 * @ingroup serf
 * @{
 */

/**
 * When a connection is established, the application needs to wrap some
 * buckets around @a skt to enable serf to process incoming responses. This
 * is the control point for assembling connection-level processing logic
 * around the given socket.
 *
 * The @a setup_baton is the baton established at connection creation time.
 *
 * This callback corresponds to reading from the server. Since this is an
 * on-demand activity, we use a callback. The corresponding write operation
 * is based on the @see serf_request_deliver function, where the application
 * can assemble the appropriate bucket(s) before delivery.
 *
 * The returned bucket should live at least as long as the connection itself.
 * It is assumed that an appropriate allocator is passed in @a setup_baton.
 * ### we may want to create a connection-level allocator and pass that
 * ### along. however, that allocator would *only* be used for this
 * ### callback. it may be wasteful to create a per-conn allocator, so this
 * ### baton-based, app-responsible form might be best.
 *
 * Responsibility for the buckets is passed to the serf library. They will be
 * destroyed when the connection is closed.
 *
 * All temporary allocations should be made in @a pool.
 */
typedef apr_status_t (*serf_connection_setup_t)(
    apr_socket_t *skt,
    serf_bucket_t **read_bkt,
    serf_bucket_t **write_bkt,
    void *setup_baton,
    apr_pool_t *pool);

/**
 * ### need to update docco w.r.t socket. became "stream" recently.
 * ### the stream does not have a barrier, this callback should generally
 * ### add a barrier around the stream before incorporating it into a
 * ### response bucket stack.
 * ### should serf add the barrier automatically to protect its data
 * ### structure? i.e. the passed bucket becomes owned rather than
 * ### borrowed. that might suit overall semantics better.
 * Accept an incoming response for @a request, and its @a socket. A bucket
 * for the response should be constructed and returned. This is the control
 * point for assembling the appropriate wrapper buckets around the socket to
 * enable processing of the incoming response.
 *
 * The @a acceptor_baton is the baton provided when the specified request
 * was created.
 *
 * The request's pool and bucket allocator should be used for any allocations
 * that need to live for the duration of the response. Care should be taken
 * to bound the amount of memory stored in this pool -- to ensure that
 * allocations are not proportional to the amount of data in the response.
 *
 * Responsibility for the bucket is passed to the serf library. It will be
 * destroyed when the response has been fully read (the bucket returns an
 * APR_EOF status from its read functions).
 *
 * All temporary allocations should be made in @a pool.
 */
/* ### do we need to return an error? */
typedef serf_bucket_t * (*serf_response_acceptor_t)(
    serf_request_t *request,
    serf_bucket_t *stream,
    void *acceptor_baton,
    apr_pool_t *pool);

/**
 * Notification callback for when a connection closes.
 *
 * This callback is used to inform an application that the @a conn
 * connection has been (abnormally) closed. The @a closed_baton is the
 * baton provided when the connection was first opened. The reason for
 * closure is given in @a why, and will be APR_SUCCESS if the application
 * requested closure (by clearing the pool used to allocate this
 * connection or calling serf_connection_close).
 *
 * All temporary allocations should be made in @a pool.
 */
typedef void (*serf_connection_closed_t)(
    serf_connection_t *conn,
    void *closed_baton,
    apr_status_t why,
    apr_pool_t *pool);

/**
 * Response data has arrived and should be processed.
 *
 * Whenever response data for @a request arrives (initially, or continued data
 * arrival), this handler is invoked. The response data is available in the
 * @a response bucket. The @a handler_baton is passed along from the baton
 * provided by the request setup callback (@see serf_request_setup_t).
 *
 * The handler MUST process data from the @a response bucket until the
 * bucket's read function states it would block (see APR_STATUS_IS_EAGAIN).
 * The handler is invoked only when new data arrives. If no further data
 * arrives, and the handler does not process all available data, then the
 * system can result in a deadlock around the unprocessed, but read, data.
 *
 * The handler should return APR_EOF when the response has been fully read.
 * If calling the handler again would block, APR_EAGAIN should be returned.
 * If the handler should be invoked again, simply return APR_SUCCESS.
 *
 * Note: if the connection closed (at the request of the application, or
 * because of an (abnormal) termination) while a request is being delivered,
 * or before a response arrives, then @a response will be NULL. This is the
 * signal that the request was not delivered properly, and no further
 * response should be expected (this callback will not be invoked again).
 * If a request is injected into the connection (during this callback's
 * execution, or otherwise), then the connection will be reopened.
 *
 * All temporary allocations should be made in @a pool.
 */
typedef apr_status_t (*serf_response_handler_t)(
    serf_request_t *request,
    serf_bucket_t *response,
    void *handler_baton,
    apr_pool_t *pool);

/**
 * Callback function to be implemented by the application, so that serf
 * can handle server and proxy authentication.
 * code = 401 (server) or 407 (proxy).
 * baton = the baton passed to serf_context_run.
 * authn_type = one of "Basic", "Digest".
 */
typedef apr_status_t (*serf_credentials_callback_t)(
    char **username,
    char **password,
    serf_request_t *request, void *baton,
    int code, const char *authn_type,
    const char *realm,
    apr_pool_t *pool);

/**
 * Create a new connection associated with the @a ctx serf context.
 *
 * If no proxy server is configured, a connection will be created to
 * (eventually) connect to the address specified by @a address. The address must
 * live at least as long as @a pool (thus, as long as the connection object).
 * If a proxy server is configured, @address will be ignored.
 *
 * The connection object will be allocated within @a pool. Clearing or
 * destroying this pool will close the connection, and terminate any
 * outstanding requests or responses.
 *
 * When the connection is closed (upon request or because of an error),
 * then the @a closed callback is invoked, and @a closed_baton is passed.
 *
 * ### doc on setup(_baton). tweak below comment re: acceptor.
 * NULL may be passed for @a acceptor and @a closed; default implementations
 * will be used.
 *
 * Note: the connection is not made immediately. It will be opened on
 * the next call to @see serf_context_run.
 */
serf_connection_t *serf_connection_create(
    serf_context_t *ctx,
    apr_sockaddr_t *address,
    serf_connection_setup_t setup,
    void *setup_baton,
    serf_connection_closed_t closed,
    void *closed_baton,
    apr_pool_t *pool);

/**
 * Create a new connection associated with the @a ctx serf context.
 *
 * A connection will be created to (eventually) connect to the address
 * specified by @a address. The address must live at least as long as
 * @a pool (thus, as long as the connection object).
 *
 * The host address will be looked up based on the hostname in @a host_info.
 *
 * The connection object will be allocated within @a pool. Clearing or
 * destroying this pool will close the connection, and terminate any
 * outstanding requests or responses.
 *
 * When the connection is closed (upon request or because of an error),
 * then the @a closed callback is invoked, and @a closed_baton is passed.
 *
 * ### doc on setup(_baton). tweak below comment re: acceptor.
 * NULL may be passed for @a acceptor and @a closed; default implementations
 * will be used.
 *
 * Note: the connection is not made immediately. It will be opened on
 * the next call to @see serf_context_run.
 */
apr_status_t serf_connection_create2(
    serf_connection_t **conn,
    serf_context_t *ctx,
    apr_uri_t host_info,
    serf_connection_setup_t setup,
    void *setup_baton,
    serf_connection_closed_t closed,
    void *closed_baton,
    apr_pool_t *pool);

typedef apr_status_t (*serf_accept_client_t)(
    serf_context_t *ctx,
    serf_listener_t *l,
    void *accept_baton,
    apr_socket_t *insock,
    apr_pool_t *pool);

apr_status_t serf_listener_create(
    serf_listener_t **listener,
    serf_context_t *ctx,
    const char *host,
    apr_uint16_t port,
    void *accept_baton,
    serf_accept_client_t accept_func,
    apr_pool_t *pool);

typedef apr_status_t (*serf_incoming_request_cb_t)(
    serf_context_t *ctx,
    serf_incoming_request_t *req,
    void *request_baton,
    apr_pool_t *pool);

apr_status_t serf_incoming_create(
    serf_incoming_t **client,
    serf_context_t *ctx,
    apr_socket_t *insock,
    void *request_baton,
    serf_incoming_request_cb_t request,
    apr_pool_t *pool);

/**
 * Reset the connection, but re-open the socket again.
 */
apr_status_t serf_connection_reset(
    serf_connection_t *conn);

/**
 * Close the connection associated with @a conn and cancel all pending requests.
 *
 * The closed callback passed to serf_connection_create() will be invoked
 * with APR_SUCCESS.
 */
apr_status_t serf_connection_close(
    serf_connection_t *conn);

/**
 * Sets the maximum number of outstanding requests @a max_requests on the
 * connection @a conn. Setting max_requests to 0 means unlimited (the default).
 * Ex.: setting max_requests to 1 means a request is sent when a response on the
 * previous request was received and handled.
 *
 * In general, serf tends to take around 16KB per outstanding request.
 */
void serf_connection_set_max_outstanding_requests(
    serf_connection_t *conn,
    unsigned int max_requests);

void serf_connection_set_async_responses(
    serf_connection_t *conn,
    serf_response_acceptor_t acceptor,
    void *acceptor_baton,
    serf_response_handler_t handler,
    void *handler_baton);

/**
 * Setup the @a request for delivery on its connection.
 *
 * Right before this is invoked, @a pool will be built within the
 * connection's pool for the request to use.  The associated response will
 * be allocated within that subpool. An associated bucket allocator will
 * be built. These items may be fetched from the request object through
 * @see serf_request_get_pool or @see serf_request_get_alloc.
 *
 * The content of the request is specified by the @a req_bkt bucket. When
 * a response arrives, the @a acceptor callback will be invoked (along with
 * the @a acceptor_baton) to produce a response bucket. That bucket will then
 * be passed to @a handler, along with the @a handler_baton.
 *
 * The responsibility for the request bucket is passed to the request
 * object. When the request is done with the bucket, it will be destroyed.
 */
typedef apr_status_t (*serf_request_setup_t)(
    serf_request_t *request,
    void *setup_baton,
    serf_bucket_t **req_bkt,
    serf_response_acceptor_t *acceptor,
    void **acceptor_baton,
    serf_response_handler_t *handler,
    void **handler_baton,
    apr_pool_t *pool);

/**
 * Construct a request object for the @a conn connection.
 *
 * When it is time to deliver the request, the @a setup callback will
 * be invoked with the @a setup_baton passed into it to complete the
 * construction of the request object.
 *
 * If the request has not (yet) been delivered, then it may be canceled
 * with @see serf_request_cancel.
 *
 * Invoking any calls other than @see serf_request_cancel before the setup
 * callback executes is not supported.
 */
serf_request_t *serf_connection_request_create(
    serf_connection_t *conn,
    serf_request_setup_t setup,
    void *setup_baton);

/**
 * Construct a request object for the @a conn connection, add it in the
 * list as the next to-be-written request before all unwritten requests.
 *
 * When it is time to deliver the request, the @a setup callback will
 * be invoked with the @a setup_baton passed into it to complete the
 * construction of the request object.
 *
 * If the request has not (yet) been delivered, then it may be canceled
 * with @see serf_request_cancel.
 *
 * Invoking any calls other than @see serf_request_cancel before the setup
 * callback executes is not supported.
 */
serf_request_t *serf_connection_priority_request_create(
    serf_connection_t *conn,
    serf_request_setup_t setup,
    void *setup_baton);

/** Returns detected network latency for the @a conn connection. Negative
 *  value means that latency is unknwon.
 */
apr_interval_time_t serf_connection_get_latency(serf_connection_t *conn);

/** Check if a @a request has been completely written.
 *
 * Returns APR_SUCCESS if the request was written completely on the connection.
 * Returns APR_EBUSY if the request is not yet or partially written.
 */
apr_status_t serf_request_is_written(
    serf_request_t *request);

/**
 * Cancel the request specified by the @a request object.
 *
 * If the request has been scheduled for delivery, then its response
 * handler will be run, passing NULL for the response bucket.
 *
 * If the request has already been (partially or fully) delivered, then
 * APR_EBUSY is returned and the request is *NOT* canceled. To properly
 * cancel the request, the connection must be closed (by clearing or
 * destroying its associated pool).
 */
apr_status_t serf_request_cancel(
    serf_request_t *request);

/**
 * Return the pool associated with @a request.
 *
 * WARNING: be very careful about the kinds of things placed into this
 * pool. In particular, all allocation should be bounded in size, rather
 * than proportional to any data stream.
 */
apr_pool_t *serf_request_get_pool(
    const serf_request_t *request);

/**
 * Return the bucket allocator associated with @a request.
 */
serf_bucket_alloc_t *serf_request_get_alloc(
    const serf_request_t *request);

/**
 * Return the connection associated with @a request.
 */
serf_connection_t *serf_request_get_conn(
    const serf_request_t *request);

/**
 * Update the @a handler and @a handler_baton for this @a request.
 *
 * This can be called after the request has started processing -
 * subsequent data will be delivered to this new handler.
 */
void serf_request_set_handler(
    serf_request_t *request,
    const serf_response_handler_t handler,
    const void **handler_baton);

/**
 * Configure proxy server settings, to be used by all connections associated
 * with the @a ctx serf context.
 *
 * The next connection will be created to connect to the proxy server
 * specified by @a address. The address must live at least as long as the
 * serf context.
 */
void serf_config_proxy(
    serf_context_t *ctx,
    apr_sockaddr_t *address);

/* Supported authentication types. */
#define SERF_AUTHN_NONE      0x00
#define SERF_AUTHN_BASIC     0x01
#define SERF_AUTHN_DIGEST    0x02
#define SERF_AUTHN_NTLM      0x04
#define SERF_AUTHN_NEGOTIATE 0x08
#define SERF_AUTHN_ALL       0xFF

/**
 * Define the authentication handlers that serf will try on incoming requests.
 */
void serf_config_authn_types(
    serf_context_t *ctx,
    int authn_types);

/**
 * Set the credentials callback handler.
 */
void serf_config_credentials_callback(
    serf_context_t *ctx,
    serf_credentials_callback_t cred_cb);

/* ### maybe some connection control functions for flood? */

/*** Special bucket creation functions ***/

/**
 * Create a bucket of type 'socket bucket'.
 * This is basically a wrapper around @a serf_bucket_socket_create, which
 * initializes the bucket using connection and/or context specific settings.
 */
serf_bucket_t *serf_context_bucket_socket_create(
    serf_context_t *ctx,
    apr_socket_t *skt,
    serf_bucket_alloc_t *allocator);

/**
 * Create a bucket of type 'request bucket'.
 * This is basically a wrapper around @a serf_bucket_request_create, which
 * initializes the bucket using request, connection and/or context specific
 * settings.
 *
 * This function will set following header(s):
 * - Host: if the connection was created with @a serf_connection_create2.
 */
serf_bucket_t *serf_request_bucket_request_create(
    serf_request_t *request,
    const char *method,
    const char *uri,
    serf_bucket_t *body,
    serf_bucket_alloc_t *allocator);

/** @} */

/**
 * @defgroup serf buckets
 * @ingroup serf
 * @{
 */

/** Pass as REQUESTED to the read function of a bucket to read, consume,
 * and return all available data.
 */
#define SERF_READ_ALL_AVAIL ((apr_size_t)-1)

/** Acceptable newline types for bucket->readline(). */
#define SERF_NEWLINE_CR    0x0001
#define SERF_NEWLINE_CRLF  0x0002
#define SERF_NEWLINE_LF    0x0004
#define SERF_NEWLINE_ANY   0x0007

/** Used to indicate that a newline is not present in the data buffer. */
/* ### should we make this zero? */
#define SERF_NEWLINE_NONE  0x0008

/** Used to indicate that a CR was found at the end of a buffer, and CRLF
 * was acceptable. It may be that the LF is present, but it needs to be
 * read first.
 *
 * Note: an alternative to using this symbol would be for callers to see
 * the SERF_NEWLINE_CR return value, and know that some "end of buffer" was
 * reached. While this works well for @see serf_util_readline, it does not
 * necessary work as well for buckets (there is no obvious "end of buffer",
 * although there is an "end of bucket"). The other problem with that
 * alternative is that developers might miss the condition. This symbol
 * calls out the possibility and ensures that callers will watch for it.
 */
#define SERF_NEWLINE_CRLF_SPLIT 0x0010

struct serf_bucket_type_t {

    /** name of this bucket type */
    const char *name;

    /**
     * Read (and consume) up to @a requested bytes from @a bucket.
     *
     * A pointer to the data will be returned in @a data, and its length
     * is specified by @a len.
     *
     * The data will exist until one of two conditions occur:
     *
     * 1) this bucket is destroyed
     * 2) another call to any read function or to peek()
     *
     * If an application needs the data to exist for a longer duration,
     * then it must make a copy.
     */
    apr_status_t (*read)(serf_bucket_t *bucket, apr_size_t requested,
                         const char **data, apr_size_t *len);

    /**
     * Read (and consume) a line of data from @a bucket.
     *
     * The acceptable forms of a newline are given by @a acceptable, and
     * the type found is returned in @a found. If a newline is not present
     * in the returned data, then SERF_NEWLINE_NONE is stored into @a found.
     *
     * A pointer to the data is returned in @a data, and its length is
     * specified by @a len. The data will include the newline, if present.
     *
     * Note that there is no way to limit the amount of data returned
     * by this function.
     *
     * The lifetime of the data is the same as that of the @see read
     * function above.
     */
    apr_status_t (*readline)(serf_bucket_t *bucket, int acceptable,
                             int *found,
                             const char **data, apr_size_t *len);

    /**
     * Read a set of pointer/length pairs from the bucket.
     *
     * The size of the @a vecs array is specified by @a vecs_size. The
     * bucket should fill in elements of the array, and return the number
     * used in @a vecs_used.
     *
     * Each element of @a vecs should specify a pointer to a block of
     * data and a length of that data.
     *
     * The total length of all data elements should not exceed the
     * amount specified in @a requested.
     *
     * The lifetime of the data is the same as that of the @see read
     * function above.
     */
    apr_status_t (*read_iovec)(serf_bucket_t *bucket, apr_size_t requested,
                               int vecs_size, struct iovec *vecs,
                               int *vecs_used);

    /**
     * Read data from the bucket in a form suitable for apr_socket_sendfile()
     *
     * On input, hdtr->numheaders and hdtr->numtrailers specify the size
     * of the hdtr->headers and hdtr->trailers arrays, respectively. The
     * bucket should fill in the headers and trailers, up to the specified
     * limits, and set numheaders and numtrailers to the number of iovecs
     * filled in for each item.
     *
     * @a file should be filled in with a file that can be read. If a file
     * is not available or appropriate, then NULL should be stored. The
     * file offset for the data should be stored in @a offset, and the
     * length of that data should be stored in @a len. If a file is not
     * returned, then @a offset and @a len should be ignored.
     *
     * The file position is not required to correspond to @a offset, and
     * the caller may manipulate it at will.
     *
     * The total length of all data elements, and the portion of the
     * file should not exceed the amount specified in @a requested.
     *
     * The lifetime of the data is the same as that of the @see read
     * function above.
     */
    apr_status_t (*read_for_sendfile)(serf_bucket_t *bucket,
                                      apr_size_t requested, apr_hdtr_t *hdtr,
                                      apr_file_t **file, apr_off_t *offset,
                                      apr_size_t *len);

    /**
     * Look within @a bucket for a bucket of the given @a type. The bucket
     * must be the "initial" data because it will be consumed by this
     * function. If the given bucket type is available, then read and consume
     * it, and return it to the caller.
     *
     * This function is usually used by readers that have custom handling
     * for specific bucket types (e.g. looking for a file bucket to pass
     * to apr_socket_sendfile).
     *
     * If a bucket of the given type is not found, then NULL is returned.
     *
     * The returned bucket becomes the responsibility of the caller. When
     * the caller is done with the bucket, it should be destroyed.
     */
    serf_bucket_t * (*read_bucket)(serf_bucket_t *bucket,
                                   const serf_bucket_type_t *type);

    /**
     * Peek, but don't consume, the data in @a bucket.
     *
     * Since this function is non-destructive, the implicit read size is
     * SERF_READ_ALL_AVAIL. The caller can then use whatever amount is
     * appropriate.
     *
     * The @a data parameter will point to the data, and @a len will
     * specify how much data is available. The lifetime of the data follows
     * the same rules as the @see read function above.
     *
     * Note: if the peek does not return enough data for your particular
     * use, then you must read/consume some first, then peek again.
     *
     * If the returned data represents all available data, then APR_EOF
     * will be returned. Since this function does not consume data, it
     * can return the same data repeatedly rather than blocking; thus,
     * APR_EAGAIN will never be returned.
     */
    apr_status_t (*peek)(serf_bucket_t *bucket,
                         const char **data, apr_size_t *len);

    /**
     * Destroy @a bucket, along with any associated resources.
     */
    void (*destroy)(serf_bucket_t *bucket);

    /* ### apr buckets have 'copy', 'split', and 'setaside' functions.
       ### not sure whether those will be needed in this bucket model.
    */
};

/**
 * Should the use and lifecycle of buckets be tracked?
 *
 * When tracking, the system will ensure several semantic requirements
 * of bucket use:
 *
 *   - if a bucket returns APR_EAGAIN, one of its read functions should
 *     not be called immediately. the context's run loop should be called.
 *     ### and for APR_EOF, too?
 *   - all buckets must be drained of input before returning to the
 *     context's run loop.
 *   - buckets should not be destroyed before they return APR_EOF unless
 *     the connection is closed for some reason.
 *
 * Undefine this symbol to avoid the tracking (and a performance gain).
 *
 * ### we may want to examine when/how we provide this. should it always
 * ### be compiled in? and apps select it before including this header?
 */
/* #define SERF_DEBUG_BUCKET_USE */

/* Internal macros for tracking bucket use. */
#ifdef SERF_DEBUG_BUCKET_USE
#define SERF__RECREAD(b,s) serf_debug__record_read(b,s)
#else
#define SERF__RECREAD(b,s) (s)
#endif

#define serf_bucket_read(b,r,d,l) SERF__RECREAD(b, (b)->type->read(b,r,d,l))
#define serf_bucket_readline(b,a,f,d,l) \
    SERF__RECREAD(b, (b)->type->readline(b,a,f,d,l))
#define serf_bucket_read_iovec(b,r,s,v,u) \
    SERF__RECREAD(b, (b)->type->read_iovec(b,r,s,v,u))
#define serf_bucket_read_for_sendfile(b,r,h,f,o,l) \
    SERF__RECREAD(b, (b)->type->read_for_sendfile(b,r,h,f,o,l))
#define serf_bucket_read_bucket(b,t) ((b)->type->read_bucket(b,t))
#define serf_bucket_peek(b,d,l) ((b)->type->peek(b,d,l))
#define serf_bucket_destroy(b) ((b)->type->destroy(b))

/**
 * Check whether a real error occurred. Note that bucket read functions
 * can return EOF and EAGAIN as part of their "normal" operation, so they
 * should not be considered an error.
 */
#define SERF_BUCKET_READ_ERROR(status) ((status) \
                                        && !APR_STATUS_IS_EOF(status) \
                                        && !APR_STATUS_IS_EAGAIN(status) \
                                        && (SERF_ERROR_WAIT_CONN != status))

struct serf_bucket_t {

    /** the type of this bucket */
    const serf_bucket_type_t *type;

    /** bucket-private data */
    void *data;

    /** the allocator used for this bucket (needed at destroy time) */
    serf_bucket_alloc_t *allocator;
};

/**
 * Generic macro to construct "is TYPE" macros.
 */
#define SERF_BUCKET_CHECK(b, btype) ((b)->type == &serf_bucket_type_ ## btype)

/**
 * Notification callback for a block that was not returned to the bucket
 * allocator when its pool was destroyed.
 *
 * The block of memory is given by @a block. The baton provided when the
 * allocator was constructed is passed as @a unfreed_baton.
 */
typedef void (*serf_unfreed_func_t)(
    void *unfreed_baton,
    void *block);

/**
 * Create a new allocator for buckets.
 *
 * All buckets are associated with a serf bucket allocator. This allocator
 * will be created within @a pool and will be destroyed when that pool is
 * cleared or destroyed.
 *
 * When the allocator is destroyed, if any allocations were not explicitly
 * returned (by calling serf_bucket_mem_free), then the @a unfreed callback
 * will be invoked for each block. @a unfreed_baton will be passed to the
 * callback.
 *
 * If @a unfreed is NULL, then the library will invoke the abort() stdlib
 * call. Any failure to return memory is a bug in the application, and an
 * abort can assist with determining what kinds of memory were not freed.
 */
serf_bucket_alloc_t *serf_bucket_allocator_create(
    apr_pool_t *pool,
    serf_unfreed_func_t unfreed,
    void *unfreed_baton);

/**
 * Return the pool that was used for this @a allocator.
 *
 * WARNING: the use of this pool for allocations requires a very
 *   detailed understanding of pool behaviors, the bucket system,
 *   and knowledge of the bucket's use within the overall pattern
 *   of request/response behavior.
 *
 * See design-guide.txt for more information about pool usage.
 */
apr_pool_t *serf_bucket_allocator_get_pool(
    const serf_bucket_alloc_t *allocator);

/**
 * Utility structure for reading a complete line of input from a bucket.
 *
 * Since it is entirely possible for a line to be broken by APR_EAGAIN,
 * this structure can be used to accumulate the data until a complete line
 * has been read from a bucket.
 */

/* This limit applies to the line buffer functions. If an application needs
 * longer lines, then they will need to manually handle line buffering.
 */
#define SERF_LINEBUF_LIMIT 8000

typedef struct {

    /* Current state of the buffer. */
    enum {
        SERF_LINEBUF_EMPTY,
        SERF_LINEBUF_READY,
        SERF_LINEBUF_PARTIAL,
        SERF_LINEBUF_CRLF_SPLIT
    } state;

    /* How much of the buffer have we used? */
    apr_size_t used;

    /* The line is read into this buffer, minus CR/LF */
    char line[SERF_LINEBUF_LIMIT];

} serf_linebuf_t;

/**
 * Initialize the @a linebuf structure.
 */
void serf_linebuf_init(serf_linebuf_t *linebuf);

/**
 * Fetch a line of text from @a bucket, accumulating the line into
 * @a linebuf. @a acceptable specifies the types of newlines which are
 * acceptable for this fetch.
 *
 * ### we should return a data/len pair so that we can avoid a copy,
 * ### rather than having callers look into our state and line buffer.
 */
apr_status_t serf_linebuf_fetch(
    serf_linebuf_t *linebuf,
    serf_bucket_t *bucket,
    int acceptable);

/** @} */

/* Internal functions for bucket use and lifecycle tracking */
apr_status_t serf_debug__record_read(
    const serf_bucket_t *bucket,
    apr_status_t status);
void serf_debug__entered_loop(
    serf_bucket_alloc_t *allocator);
void serf_debug__closed_conn(
    serf_bucket_alloc_t *allocator);
void serf_debug__bucket_destroy(
    const serf_bucket_t *bucket);
void serf_debug__bucket_alloc_check(
    serf_bucket_alloc_t *allocator);

/* Version info */
#define SERF_MAJOR_VERSION 1
#define SERF_MINOR_VERSION 3
#define SERF_PATCH_VERSION 1

/* Version number string */
#define SERF_VERSION_STRING APR_STRINGIFY(SERF_MAJOR_VERSION) "." \
                            APR_STRINGIFY(SERF_MINOR_VERSION) "." \
                            APR_STRINGIFY(SERF_PATCH_VERSION)

/**
 * Check at compile time if the Serf version is at least a certain
 * level.
 * @param major The major version component of the version checked
 * for (e.g., the "1" of "1.3.0").
 * @param minor The minor version component of the version checked
 * for (e.g., the "3" of "1.3.0").
 * @param patch The patch level component of the version checked
 * for (e.g., the "0" of "1.3.0").
 */
#define SERF_VERSION_AT_LEAST(major,minor,patch)                         \
(((major) < SERF_MAJOR_VERSION)                                          \
  || ((major) == SERF_MAJOR_VERSION && (minor) < SERF_MINOR_VERSION)     \
   || ((major) == SERF_MAJOR_VERSION && (minor) == SERF_MINOR_VERSION && \
            (patch) <= SERF_PATCH_VERSION))

/**
 * Returns the version of the library the application has linked/loaded.
 * Values are returned in @a major, @a minor, and @a patch.
 *
 * Applications will want to use this function to verify compatibility,
 * expecially while serf has not reached a 1.0 milestone. APIs and
 * semantics may change drastically until the library hits 1.0.
 */
void serf_lib_version(
    int *major,
    int *minor,
    int *patch);

#ifdef __cplusplus
}
#endif

/*
 * Every user of serf will want to deal with our various bucket types.
 * Go ahead and include that header right now.
 *
 * Note: make sure this occurs outside of the C++ namespace block
 */
#include "serf_bucket_types.h"

#endif    /* !SERF_H */


text:
package org.apache.ignite.internal.processors.query.h2.database.io;

import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.internal.pagemem.PageUtils;
import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree;
import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO;
import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusLeafIO;
import org.apache.ignite.internal.processors.query.h2.database.H2Tree;
import org.apache.ignite.internal.processors.query.h2.opt.H2CacheRow;
import org.apache.ignite.internal.processors.query.h2.opt.H2Row;

/**
 * Leaf page for H2 row references.
 */
public abstract class AbstractH2LeafIO extends BPlusLeafIO<H2Row> implements H2RowLinkIO {
    /**
     * @param type Page type.
     * @param ver Page format version.
     * @param itemSize Single item size on page.
     */
    AbstractH2LeafIO(int type, int ver, int itemSize) {
        super(type, ver, itemSize);
    }

    /** {@inheritDoc} */
    @Override public final void storeByOffset(long pageAddr, int off, H2Row row) {
        H2CacheRow row0 = (H2CacheRow)row;

        H2IOUtils.storeRow(row0, pageAddr, off, storeMvccInfo());
    }

    /** {@inheritDoc} */
    @Override public final void store(long dstPageAddr, int dstIdx, BPlusIO<H2Row> srcIo, long srcPageAddr, int srcIdx) {
        assert srcIo == this;

        H2IOUtils.store(dstPageAddr, offset(dstIdx), srcIo, srcPageAddr, srcIdx, storeMvccInfo());
    }

    /** {@inheritDoc} */
    @Override public final H2Row getLookupRow(BPlusTree<H2Row,?> tree, long pageAddr, int idx)
        throws IgniteCheckedException {
        long link = getLink(pageAddr, idx);

        if (storeMvccInfo()) {
            long mvccCrdVer = getMvccCoordinatorVersion(pageAddr, idx);
            long mvccCntr = getMvccCounter(pageAddr, idx);
            int mvccOpCntr = getMvccOperationCounter(pageAddr, idx);

            return ((H2Tree)tree).createMvccRow(link, mvccCrdVer, mvccCntr, mvccOpCntr);
        }

        return ((H2Tree)tree).createRow(link);
    }

    /** {@inheritDoc} */
    @Override public long getLink(long pageAddr, int idx) {
        return PageUtils.getLong(pageAddr, offset(idx));
    }
}