<commit_before>
#if defined(__linux__)
#include <locale.h>
#include <locale>
#include <strings.h>
#elif defined(_MSC_VER)
#include <windows.h>
#include <string.h>
#define strncasecmp     strnicmp
#endif

#include <fast_matmult/lang_def.h>

static int s_lang_id = LANG_EN_US;

#if defined(__linux__)

/// <comment>
///
/// ο: Linux²ִСдstrstr
///
/// http://blog.csdn.net/yasi_xi/article/details/7329987
///
/// </comment>

char *strstri_(const char *str, const char *str_sub)
{
    size_t len, len_sub;
    if (str == NULL || str_sub == NULL)
        return NULL;
    len = strlen(str);
    len_sub = strlen(str_sub);
    if (len_sub == 0 || len == 0 || len < len_sub)
        return NULL;

    while (*str) {
        if (strncasecmp(str, str_sub, len_sub) == 0)
            return (char *)str;
        ++str;
    }
    return NULL;
}

/// <comment>
///
/// ο:
///
/// http://stackoverflow.com/questions/12170488/how-to-get-current-locale-of-my-environment
/// http://msdn.microsoft.com/zh-cn/library/x99tb11d.aspx
///
/// </comment>

int get_sys_locale_id(void)
{
    int lang_id = LANG_NONE;
    char *locale;
    setlocale(LC_ALL, "");
    locale = setlocale(LC_ALL, NULL);
    // "zh_CN.xxxxx"
    if (strstri_(locale, "zh_cn") != NULL) {
        lang_id = LANG_ZH_CN;
    }
    // "zh_TW.xxxxx"
    else if (strstri_(locale, "zh_tw") != NULL) {
        lang_id = LANG_ZH_TW;
    }
    // "en_US.xxxxx"
    else {
        lang_id = LANG_EN_US;
    }
    return lang_id;
}

int get_user_locale_id(void)
{
    return get_sys_locale_id();
}

#elif defined(_MSC_VER)

/// <comment>
///
/// ο: Language Identifier Constants and Strings
///
///       http://msdn.microsoft.com/en-us/library/dd318693%28v=vs.85%29.aspx
///
///   : Windows Locale Codes Sorted by Locale ID (LCID), Hexadecimal
///
///       http://blog.csdn.net/cuixiping/article/details/5592291 (Է, Ƽ)
///
/// </comment>

int get_sys_locale_id(void)
{
    int lang_id = LANG_NONE;
    LCID locale_id;
    locale_id = GetSystemDefaultLCID();
    if (locale_id == 0x0804) {      /* Chinese (PRC) */
        lang_id = LANG_ZH_CN;
    }
    else if (locale_id == 0x0404    /* Chinese (Taiwan) */
        || locale_id == 0x0C04      /* Chinese (Hong Kong S.A.R.) */
        || locale_id == 0x1004      /* Chinese (Singapore) */
        || locale_id == 0x1404      /* Chinese (Macau S.A.R.) */
        ) {
        lang_id = LANG_ZH_TW;
    }
    else {
        lang_id = LANG_EN_US;       /* English (United States) is 0x0409 */
    }
    return lang_id;
}

int get_user_locale_id(void)
{
    int lang_id = LANG_NONE;
    LCID locale_id;
    locale_id = GetUserDefaultLCID();
    if (locale_id == 0x0804) {      /* Chinese (PRC) */
        lang_id = LANG_ZH_CN;
    }
    else if (locale_id == 0x0404    /* Chinese (Taiwan) */
        || locale_id == 0x0C04      /* Chinese (Hong Kong S.A.R.) */
        || locale_id == 0x1004      /* Chinese (Singapore) */
        || locale_id == 0x1404      /* Chinese (Macau S.A.R.) */
        ) {
        lang_id = LANG_ZH_TW;
    }
    else {
        lang_id = LANG_EN_US;       /* English (United States) is 0x0409 */
    }
    return lang_id;
}

#else  /* other unknown os */

int get_sys_locale_id(void)
{
    return LANG_EN_US;
}

int get_user_locale_id(void)
{
    return LANG_EN_US;
}

#endif  /* __linux__ */

int get_current_langid(void)
{
    return s_lang_id;
}

int set_current_langid(int lang_id)
{
    int old_lang_id = s_lang_id;
    if (lang_id == LANG_USER || lang_id < 0) {
        s_lang_id = get_user_locale_id();
        return s_lang_id;
    }
    else if (lang_id == LANG_ZH_CN) {
        s_lang_id = LANG_ZH_CN;
    }
    else {
        s_lang_id = LANG_EN_US;
    }
    return old_lang_id;
}
<commit_msg>添加注释<commit_after>
#if defined(__linux__)
#include <locale.h>
#include <locale>
#include <strings.h>
#elif defined(_MSC_VER)
#include <windows.h>
#include <string.h>
#define strncasecmp     strnicmp
#endif

#include <fast_matmult/lang_def.h>

static int s_lang_id = LANG_EN_US;

#if defined(__linux__)

/// <comment>
///
/// ο: Linux²ִСдstrstr
///
/// http://blog.csdn.net/yasi_xi/article/details/7329987
///
/// </comment>

char *strstri_(const char *str, const char *str_sub)
{
    size_t len, len_sub;
    if (str == NULL || str_sub == NULL)
        return NULL;
    len = strlen(str);
    len_sub = strlen(str_sub);
    if (len_sub == 0 || len == 0 || len < len_sub)
        return NULL;

    while (*str) {
        if (strncasecmp(str, str_sub, len_sub) == 0)
            return (char *)str;
        ++str;
    }
    return NULL;
}

/// <comment>
///
/// ο: How to get current locale of my environment?
///
/// http://stackoverflow.com/questions/12170488/how-to-get-current-locale-of-my-environment
/// http://blog.csdn.net/code_robot/article/details/5686229
/// http://msdn.microsoft.com/zh-cn/library/x99tb11d.aspx
///
/// </comment>

int get_sys_locale_id(void)
{
    char *locale;
    int lang_id = LANG_NONE;

    //  locale Ϊ "" ʱ, ݻ趨 locale
    setlocale(LC_ALL, "");
    //  locale Ϊ NULL ʱ, ֻȡصǰ locale , ֵͨ, ı䵱ǰ locale
    locale = setlocale(LC_ALL, NULL);
    // "zh_CN.xxxxx"
    if (strstri_(locale, "zh_cn") != NULL) {
        lang_id = LANG_ZH_CN;
    }
    // "zh_TW.xxxxx"
    else if (strstri_(locale, "zh_tw") != NULL) {
        lang_id = LANG_ZH_TW;
    }
    // "en_US.xxxxx"
    else {
        lang_id = LANG_EN_US;
    }
    return lang_id;
}

int get_user_locale_id(void)
{
    return get_sys_locale_id();
}

#elif defined(_MSC_VER)

/// <comment>
///
/// ο: Language Identifier Constants and Strings
///
///       http://msdn.microsoft.com/en-us/library/dd318693%28v=vs.85%29.aspx
///
///   : Windows Locale Codes Sorted by Locale ID (LCID), Hexadecimal
///
///       http://blog.csdn.net/cuixiping/article/details/5592291 (Է, Ƽ)
///
/// </comment>

int get_sys_locale_id(void)
{
    int lang_id = LANG_NONE;
    LCID locale_id;
    locale_id = GetSystemDefaultLCID();
    if (locale_id == 0x0804) {      /* Chinese (PRC) */
        lang_id = LANG_ZH_CN;
    }
    else if (locale_id == 0x0404    /* Chinese (Taiwan) */
        || locale_id == 0x0C04      /* Chinese (Hong Kong S.A.R.) */
        || locale_id == 0x1004      /* Chinese (Singapore) */
        || locale_id == 0x1404      /* Chinese (Macau S.A.R.) */
        ) {
        lang_id = LANG_ZH_TW;
    }
    else {
        lang_id = LANG_EN_US;       /* English (United States) is 0x0409 */
    }
    return lang_id;
}

int get_user_locale_id(void)
{
    int lang_id = LANG_NONE;
    LCID locale_id;
    locale_id = GetUserDefaultLCID();
    if (locale_id == 0x0804) {      /* Chinese (PRC) */
        lang_id = LANG_ZH_CN;
    }
    else if (locale_id == 0x0404    /* Chinese (Taiwan) */
        || locale_id == 0x0C04      /* Chinese (Hong Kong S.A.R.) */
        || locale_id == 0x1004      /* Chinese (Singapore) */
        || locale_id == 0x1404      /* Chinese (Macau S.A.R.) */
        ) {
        lang_id = LANG_ZH_TW;
    }
    else {
        lang_id = LANG_EN_US;       /* English (United States) is 0x0409 */
    }
    return lang_id;
}

#else  /* other unknown os */

int get_sys_locale_id(void)
{
    return LANG_EN_US;
}

int get_user_locale_id(void)
{
    return LANG_EN_US;
}

#endif  /* __linux__ */

int get_current_langid(void)
{
    return s_lang_id;
}

int set_current_langid(int lang_id)
{
    int old_lang_id = s_lang_id;
    if (lang_id == LANG_USER || lang_id < 0) {
        s_lang_id = get_user_locale_id();
        return s_lang_id;
    }
    else if (lang_id == LANG_ZH_CN) {
        s_lang_id = LANG_ZH_CN;
    }
    else {
        s_lang_id = LANG_EN_US;
    }
    return old_lang_id;
}
<|endoftext|>


<commit_before>#pragma once

#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>

#include "angle.hpp"
#include "fp_utils.hpp"
#include "global_config.hpp"

#define GEOM_EPS 1e-13

namespace {
    template <typename T> int sgn(T val) {
        return (T(0) < val) - (val < T(0));
    }
}

namespace mocc {
    class Point2 {
    public:
        real_t x;
        real_t y;
        bool ok;

        Point2() {
            ok=false;
            return;
        }
        Point2(real_t x, real_t y):
            x(x), y(y), ok(true)
        {

        }

        // return the euclidian distance between the point and another point
        real_t distance(Point2 p) {
            return sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));
        }

        // Provide stream insertion support
        friend std::ostream& operator<<(std::ostream& os, const Point2 &p) {
            os << "[ " << p.x << ", " << p.y << " ]";
            return os;
        }
        /**
         * \todo Inconsistency between comment and implementation
         * comment: x-coordinate; implementation: y value?
         */
        // Overload the < operator. A point is considered "less than" another
        // point if it has a smaller x-coordinate
        bool operator<(const Point2 &other) const {
            return y < other.y;
        }

        // Point equivalence is based upon approximate floating point
        // arithmetic. Two points are equivalent if their coordinates are "close
        // enough."
        bool operator==(const Point2 &other) const {
            return fp_equiv_abs(x, other.x) && fp_equiv_abs(y, other.y);
        }

        // Vector-like subtraction of two points
        Point2& operator-=(const Point2 &other) {
            x -= other.x;
            y -= other.y;
            return *this;
        }

        // Vector-like subtraction two points
        const Point2 operator-(const Point2 &other) {
            return Point2(*this) -= other;
        }

        // Return the angle, in radians, made by the line from the origin to the
        // point from the positive-x axis. This uses atan2 and some other
        // jiggery to force the result to lie in [0,2PI]
        real_t alpha() const {
            if(y > 0.0) {
                return atan2(y, x);
            } else {
                return atan2(y, x)+TWOPI;
            }
        }
    private:
    };

    class Box {
    public:
        Box( Point2 p1, Point2 p2 ) {
            p1_ = Point2( std::min(p1.x, p2.x), std::min(p1.y, p2.y) );
            p2_ = Point2( std::max(p1.x, p2.x), std::max(p1.y, p2.y) );

            return;
        }

        Point2 intersect( Point2 p, Angle ang ) {
            // Project ox/oy to 2D plane
            real_t ox = cos(ang.alpha);
            real_t oy = sin(ang.alpha);

            // Dont use this code for astronomy stuff
            real_t d_min = 1.0e12;
            real_t d;
            real_t x, y;

            Point2 p_out;

            // Check distance to x-normal planes
            x = p1_.x;
            d = ( p1_.x - p.x ) / ox;
            y = p.y+oy*d;
            if ( (fabs(d) > GEOM_EPS) & (d < d_min) & (y > p1_.y) & (y < p2_.y )) {
                d_min = fabs(d);
                p_out.x = x;
                p_out.y = y;
                p_out.ok = true;
            }

            x = p2_.x;
            d = ( p2_.x - p.x ) / ox;
            y = p.y+oy*d;
            if ( (fabs(d) > GEOM_EPS) & (d < d_min) & (y > p1_.y) & (y < p2_.y) ) {
                d_min = fabs(d);
                p_out.x = x;
                p_out.y = y;
                p_out.ok = true;
            }

            // Check distance to y-normal planes
            y = p1_.y;
            d = ( p1_.y - p.y ) / oy;
            x = p.x+ox*d;
            if ( (fabs(d) > GEOM_EPS) & (d < d_min) & (x > p1_.x) & (x < p2_.x) ) {
                d_min = fabs(d);
                p_out.x = x;
                p_out.y = y;
                p_out.ok = true;
            }

            y = p2_.y;
            d = ( p2_.y - p.y ) / oy;
            x = p.x+ox*d;
            if ( (fabs(d) > GEOM_EPS) & (d < d_min) & (x > p1_.x) & (x < p2_.x) ) {
                d_min = fabs(d);
                p_out.x = x;
                p_out.y = y;
                p_out.ok = true;
            }

            return p_out;
        }
    private:
        // corners of the box
        Point2 p1_, p2_;

    };

    struct Circle {
        Point2 c;
        real_t r;
        Circle(Point2 c, real_t r): c(c), r(r) { }
    };

    struct Line {
        Point2 p1;
        Point2 p2;
        Line(Point2 p1, Point2 p2): p1(p1), p2(p2) { }

        friend std::ostream& operator<<( std::ostream &os, Line &l ) {
            os << "[" << l.p1 << ", " << l.p2 << "]";
            return os;
        }
    };

    inline Point2 Midpoint( const Point2 p1, const Point2 p2 ) {
        return Point2(0.5*(p1.x + p2.x), 0.5*(p1.y + p2.y));
    }

    // Intersection between a circle and a line segment. Return value carries
    // the number of valid intersections that were found
    // http://mathworld.wolfram.com/Circle-LineIntersection.html
    inline int Intersect( Line l, Circle circ, Point2 &p1, Point2 &p2 ) {
        int ret = 0;
        real_t u1 = l.p2.x - l.p1.x;
        real_t u2 = l.p2.y - l.p1.y;
        real_t w1 = l.p1.x - circ.c.x;
        real_t w2 = l.p1.y - circ.c.y;

        real_t b = w1*u1 + w2*u2;
        real_t c = w1*w1 + w2*w2 - circ.r*circ.r;
        if ( (c > 0.0) & (b > 0.0) ) {
            // no intersection
            p1.ok = false;
            p2.ok = false;
            return 0;
        }

        real_t a = u1*u1 + u2*u2;
        real_t discriminant = b*b-a*c;
        if ( discriminant < 0.0 ) {
            // No intersection
            p1.ok = false;
            p2.ok = false;
            return 0;

        } else if ( fp_equiv_rel(discriminant, 0.0) ) {
            // Tangent. Dont bother
            p1.ok = false;
            p2.ok = false;
            return 0;
        } else {
            // Whoopie, we have a couple of points
            p1.ok = true;
            p2.ok = true;

            real_t ra = 1.0/a;
            discriminant = sqrt(discriminant);
            real_t t1 = (-b-discriminant)*ra;
            real_t t2 = (-b+discriminant)*ra;
            if( (0.0 < t1) & (t1 < 1.0) ) {
                p1 = l.p1;
                p1.x += u1*t1;
                p1.y += u2*t1;
                p1.ok = true;
                ret++;
            }
            if( (0.0 < t2) & (t2 < 1.0) ) {
                // Make sure that the first point is always valid
                if (ret == 0) {
                    assert(false);
                    p1 = l.p1;
                    p1.x += u1*t2;
                    p1.y += u2*t2;
                    p1.ok = true;
                } else {
                    p2 = l.p1;
                    p2.x += u1*t2;
                    p2.y += u2*t2;
                    p2.ok = true;
                }
                ret++;
            }
            return ret;
        }
    }

    inline int Intersect( Line l1, Line l2, Point2 &p ) {
        real_t u1 = l1.p2.x - l1.p1.x;
        real_t u2 = l1.p2.y - l1.p1.y;
        real_t v1 = l2.p2.x - l2.p1.x;
        real_t v2 = l2.p2.y - l2.p1.y;
        real_t w1 = l1.p1.x - l2.p1.x;
        real_t w2 = l1.p1.y - l2.p1.y;

        real_t d = u1*v2 - u2*v1;
        real_t s = v1*w2 - v2*w1;
        real_t t = u1*w2 - u2*w1;

        if ( fabs(d) < 0.0 ) {
            // Parallel lines
            p.ok = false;
            return 0;
        }

        s = s/d;
        t = t/d;

        if ( (0.0 <= s) & (s <= 1.0) & (0.0 <= t) & (t <= 1.0) ) {
            // success
            p = l1.p1;
            p.x += s*u1;
            p.y += s*u2;
            p.ok = true;
            return 1;
        } else {
            // Intersection beyond bounds of line segments
            p.ok = false;
            return 0;
        }
    }
}
<commit_msg>Fix inconsistent comment<commit_after>#pragma once

#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>

#include "angle.hpp"
#include "fp_utils.hpp"
#include "global_config.hpp"

#define GEOM_EPS 1e-13

namespace {
    template <typename T> int sgn(T val) {
        return (T(0) < val) - (val < T(0));
    }
}

namespace mocc {
    class Point2 {
    public:
        real_t x;
        real_t y;
        bool ok;

        Point2() {
            ok=false;
            return;
        }
        Point2(real_t x, real_t y):
            x(x), y(y), ok(true)
        {

        }

        // return the euclidian distance between the point and another point
        real_t distance(Point2 p) {
            return sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));
        }

        // Provide stream insertion support
        friend std::ostream& operator<<(std::ostream& os, const Point2 &p) {
            os << "[ " << p.x << ", " << p.y << " ]";
            return os;
        }
        /**
         * A point is considered "less than" another point if it has a smaller
         * y-coordinate.
         */
        bool operator<(const Point2 &other) const {
            return y < other.y;
        }

        // Point equivalence is based upon approximate floating point
        // arithmetic. Two points are equivalent if their coordinates are "close
        // enough."
        bool operator==(const Point2 &other) const {
            return fp_equiv_abs(x, other.x) && fp_equiv_abs(y, other.y);
        }

        // Vector-like subtraction of two points
        Point2& operator-=(const Point2 &other) {
            x -= other.x;
            y -= other.y;
            return *this;
        }

        // Vector-like subtraction two points
        const Point2 operator-(const Point2 &other) {
            return Point2(*this) -= other;
        }

        // Return the angle, in radians, made by the line from the origin to the
        // point from the positive-x axis. This uses atan2 and some other
        // jiggery to force the result to lie in [0,2PI]
        real_t alpha() const {
            if(y > 0.0) {
                return atan2(y, x);
            } else {
                return atan2(y, x)+TWOPI;
            }
        }
    private:
    };

    class Box {
    public:
        Box( Point2 p1, Point2 p2 ) {
            p1_ = Point2( std::min(p1.x, p2.x), std::min(p1.y, p2.y) );
            p2_ = Point2( std::max(p1.x, p2.x), std::max(p1.y, p2.y) );

            return;
        }

        Point2 intersect( Point2 p, Angle ang ) {
            // Project ox/oy to 2D plane
            real_t ox = cos(ang.alpha);
            real_t oy = sin(ang.alpha);

            // Dont use this code for astronomy stuff
            real_t d_min = 1.0e12;
            real_t d;
            real_t x, y;

            Point2 p_out;

            // Check distance to x-normal planes
            x = p1_.x;
            d = ( p1_.x - p.x ) / ox;
            y = p.y+oy*d;
            if ( (fabs(d) > GEOM_EPS) & (d < d_min) & (y > p1_.y) & (y < p2_.y )) {
                d_min = fabs(d);
                p_out.x = x;
                p_out.y = y;
                p_out.ok = true;
            }

            x = p2_.x;
            d = ( p2_.x - p.x ) / ox;
            y = p.y+oy*d;
            if ( (fabs(d) > GEOM_EPS) & (d < d_min) & (y > p1_.y) & (y < p2_.y) ) {
                d_min = fabs(d);
                p_out.x = x;
                p_out.y = y;
                p_out.ok = true;
            }

            // Check distance to y-normal planes
            y = p1_.y;
            d = ( p1_.y - p.y ) / oy;
            x = p.x+ox*d;
            if ( (fabs(d) > GEOM_EPS) & (d < d_min) & (x > p1_.x) & (x < p2_.x) ) {
                d_min = fabs(d);
                p_out.x = x;
                p_out.y = y;
                p_out.ok = true;
            }

            y = p2_.y;
            d = ( p2_.y - p.y ) / oy;
            x = p.x+ox*d;
            if ( (fabs(d) > GEOM_EPS) & (d < d_min) & (x > p1_.x) & (x < p2_.x) ) {
                d_min = fabs(d);
                p_out.x = x;
                p_out.y = y;
                p_out.ok = true;
            }

            return p_out;
        }
    private:
        // corners of the box
        Point2 p1_, p2_;

    };

    struct Circle {
        Point2 c;
        real_t r;
        Circle(Point2 c, real_t r): c(c), r(r) { }
    };

    struct Line {
        Point2 p1;
        Point2 p2;
        Line(Point2 p1, Point2 p2): p1(p1), p2(p2) { }

        friend std::ostream& operator<<( std::ostream &os, Line &l ) {
            os << "[" << l.p1 << ", " << l.p2 << "]";
            return os;
        }
    };

    inline Point2 Midpoint( const Point2 p1, const Point2 p2 ) {
        return Point2(0.5*(p1.x + p2.x), 0.5*(p1.y + p2.y));
    }

    // Intersection between a circle and a line segment. Return value carries
    // the number of valid intersections that were found
    // http://mathworld.wolfram.com/Circle-LineIntersection.html
    inline int Intersect( Line l, Circle circ, Point2 &p1, Point2 &p2 ) {
        int ret = 0;
        real_t u1 = l.p2.x - l.p1.x;
        real_t u2 = l.p2.y - l.p1.y;
        real_t w1 = l.p1.x - circ.c.x;
        real_t w2 = l.p1.y - circ.c.y;

        real_t b = w1*u1 + w2*u2;
        real_t c = w1*w1 + w2*w2 - circ.r*circ.r;
        if ( (c > 0.0) & (b > 0.0) ) {
            // no intersection
            p1.ok = false;
            p2.ok = false;
            return 0;
        }

        real_t a = u1*u1 + u2*u2;
        real_t discriminant = b*b-a*c;
        if ( discriminant < 0.0 ) {
            // No intersection
            p1.ok = false;
            p2.ok = false;
            return 0;

        } else if ( fp_equiv_rel(discriminant, 0.0) ) {
            // Tangent. Dont bother
            p1.ok = false;
            p2.ok = false;
            return 0;
        } else {
            // Whoopie, we have a couple of points
            p1.ok = true;
            p2.ok = true;

            real_t ra = 1.0/a;
            discriminant = sqrt(discriminant);
            real_t t1 = (-b-discriminant)*ra;
            real_t t2 = (-b+discriminant)*ra;
            if( (0.0 < t1) & (t1 < 1.0) ) {
                p1 = l.p1;
                p1.x += u1*t1;
                p1.y += u2*t1;
                p1.ok = true;
                ret++;
            }
            if( (0.0 < t2) & (t2 < 1.0) ) {
                // Make sure that the first point is always valid
                if (ret == 0) {
                    assert(false);
                    p1 = l.p1;
                    p1.x += u1*t2;
                    p1.y += u2*t2;
                    p1.ok = true;
                } else {
                    p2 = l.p1;
                    p2.x += u1*t2;
                    p2.y += u2*t2;
                    p2.ok = true;
                }
                ret++;
            }
            return ret;
        }
    }

    inline int Intersect( Line l1, Line l2, Point2 &p ) {
        real_t u1 = l1.p2.x - l1.p1.x;
        real_t u2 = l1.p2.y - l1.p1.y;
        real_t v1 = l2.p2.x - l2.p1.x;
        real_t v2 = l2.p2.y - l2.p1.y;
        real_t w1 = l1.p1.x - l2.p1.x;
        real_t w2 = l1.p1.y - l2.p1.y;

        real_t d = u1*v2 - u2*v1;
        real_t s = v1*w2 - v2*w1;
        real_t t = u1*w2 - u2*w1;

        if ( fabs(d) < 0.0 ) {
            // Parallel lines
            p.ok = false;
            return 0;
        }

        s = s/d;
        t = t/d;

        if ( (0.0 <= s) & (s <= 1.0) & (0.0 <= t) & (t <= 1.0) ) {
            // success
            p = l1.p1;
            p.x += s*u1;
            p.y += s*u2;
            p.ok = true;
            return 1;
        } else {
            // Intersection beyond bounds of line segments
            p.ok = false;
            return 0;
        }
    }
}
<|endoftext|>


<commit_before>#include <catch.hpp>
#include <cmap.hpp>

using cmap::make_map;
using cmap::map;

SCENARIO("Compile time mapping") {
  GIVEN("a map of int -> int") {
    constexpr auto lookup = make_map(
        map(1,2),
        map(2,3),
	map(5,7)
    );
    THEN("chek each mapping") {
      CHECK( lookup[1] == 2 );
      CHECK( lookup[2] == 3 );
      CHECK( lookup[5] == 7 );
    }
  }

  GIVEN("a custom type") {
    struct MyType {
      constexpr bool operator==(const MyType& rhs) const { return value == rhs.value; }
      const int value;
    };
    GIVEN("a map of int -> custom type") {
      constexpr auto lookup = make_map(
          map(42, MyType{12}),
          map(43, MyType{13}),
          map(44, MyType{14})
      );
      THEN("check each mapping") {
	CHECK( lookup[42] == MyType{12} );
	CHECK( lookup[43] == MyType{13} );
	CHECK( lookup[44] == MyType{14} );
      }
    }

    GIVEN("a map of custom type -> int") {
      constexpr auto lookup = make_map(
          map(MyType{12}, 42),
          map(MyType{13}, 43),
          map(MyType{14}, 44)
      );
      THEN("check each mapping") {
        CHECK( lookup[MyType{12}] == 42 );
        CHECK( lookup[MyType{13}] == 43 );
        CHECK( lookup[MyType{14}] == 44 );
      }
    }
  }
}
<commit_msg>More tests<commit_after>#include <catch.hpp>
#include <cmap.hpp>

using cmap::make_map;
using cmap::map;

SCENARIO("Compile time mapping") {
  GIVEN("a map of int -> int") {
    constexpr auto lookup = make_map(
        map(1,2),
        map(2,3),
	map(5,7)
    );
    THEN("chek each mapping") {
      CHECK( lookup[1] == 2 );
      CHECK( lookup[2] == 3 );
      CHECK( lookup[5] == 7 );
    }
    THEN("check bad lookup (runtime)") {
      CHECK_THROWS_AS( lookup[7], std::out_of_range );
    }
    THEN("check bad lookup (compiletime)") {
      // Don't know how to check this, however the following should not compile
      // constexpr auto val = lookup[7];
    }
  }

  GIVEN("a custom type") {
    struct MyType {
      constexpr bool operator==(const MyType& rhs) const { return value == rhs.value; }
      const int value;
    };
    GIVEN("a map of int -> custom type") {
      constexpr auto lookup = make_map(
          map(42, MyType{12}),
          map(43, MyType{13}),
          map(44, MyType{14})
      );
      THEN("check each mapping") {
	CHECK( lookup[42] == MyType{12} );
	CHECK( lookup[43] == MyType{13} );
	CHECK( lookup[44] == MyType{14} );
      }
    }

    GIVEN("a map of custom type -> int") {
      constexpr auto lookup = make_map(
          map(MyType{12}, 42),
          map(MyType{13}, 43),
          map(MyType{14}, 44)
      );
      THEN("check each mapping") {
        CHECK( lookup[MyType{12}] == 42 );
        CHECK( lookup[MyType{13}] == 43 );
        CHECK( lookup[MyType{14}] == 44 );
      }
    }
  }
}
<|endoftext|>


<commit_before>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <gtest/gtest.h>
#include <af/array.h>
#include <af/arith.h>
#include <af/data.h>
#include <af/index.h>
#include <testHelpers.hpp>

using namespace std;
using namespace af;

TEST(FlipTests, Test_flip_1D)
{
    const int num = 10000;
    af::array in = randu(num);
    af::array out = flip(in, 0);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int i = 0; i < num; i++) {
        ASSERT_EQ(h_in[num - i - 1], h_out[i])
            << "at (" << i << ")";
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_2D0)
{
    const int nx = 200;
    const int ny = 200;

    af::array in = randu(nx, ny);
    af::array out = flip(in, 0);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int j = 0; j < ny; j++) {
        int off = j * nx;
        for (int i = 0; i < nx; i++) {
            ASSERT_EQ(h_in[off + nx - 1 - i], h_out[off + i])
                << "at (" << i << "," << j << ")";

        }
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_2D1)
{
    const int nx = 200;
    const int ny = 200;

    af::array in = randu(nx, ny);
    af::array out = flip(in, 1);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int j = 0; j < ny; j++) {
        int ioff = (ny - 1 - j) * nx;
        int ooff = j * nx;
        for (int i = 0; i < nx; i++) {
            ASSERT_EQ(h_in[ioff + i], h_out[ooff + i])
                << "at (" << i << "," << j << ")";
        }
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_1D_index)
{
    const int num = 10000;
    const int st = 101;
    const int en = 5000;

    af::array in = randu(num);
    af::array tmp = in(seq(st, en));
    af::array out = flip(tmp, 0);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int i = st; i <= en; i++) {
        ASSERT_EQ(h_in[i], h_out[en - i])
            << "at (" << i << ")";
    }

    delete[] h_in;
    delete[] h_out;
}

#if 0 // FIXME: Enable when this is fixed https://github.com/arrayfire/arrayfire/issues/418
TEST(FlipTests, Test_flip_2D_index00)
{
    const int nx = 200;
    const int ny = 200;
    const int st = 21;
    const int en = 180;
    const int nxo = (en - st + 1);

    af::array in = randu(nx, ny);
    af::array tmp = in(seq(st, en), span);
    af::array out = flip(tmp, 0);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int j = 0; j < ny; j++) {
        const int in_off = j * nx;
        const int out_off =j * nxo;
        for (int i = st; i <= en; i++) {
            ASSERT_EQ(h_in[i + in_off], h_out[en - i + out_off])
                << "at (" << i << "," << j << ")";
        }
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_2D_index01)
{
    const int nx = 200;
    const int ny = 200;
    const int st = 21;
    const int en = 180;
    const int nxo = (en - st + 1);

    af::array in = randu(nx, ny);
    af::array tmp = in(seq(st, en), span);
    af::array out = flip(tmp, 1);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int j = 0; j < ny; j++) {
        const int in_off = (ny - 1 - j) * nx;
        const int out_off =j * nxo;
        for (int i = st; i <= en; i++) {
            ASSERT_EQ(h_in[i + in_off], h_out[i - st + out_off])
                << "at (" << i << "," << j << ")";
        }
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_2D_index10)
{
    const int nx = 200;
    const int ny = 200;
    const int st = 21;
    const int en = 180;

    af::array in = randu(nx, ny);
    af::array tmp = in(span, seq(st, en));
    af::array out = flip(tmp, 0);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int j = st; j <= en; j++) {

        const int in_off = j * nx;
        const int out_off = (j - st) * nx;

        for (int i = 0; i < nx; i++) {
            ASSERT_EQ(h_in[nx - 1 - i + in_off], h_out[i + out_off])
                << "at (" << i << "," << j << ")";
        }
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_2D_index11)
{
    const int nx = 200;
    const int ny = 200;
    const int st = 21;
    const int en = 180;

    af::array in = randu(nx, ny);
    af::array tmp = in(span, seq(st, en));
    af::array out = flip(tmp, 1);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int j = st; j <= en; j++) {

        const int in_off = (en - j) * nx;
        const int out_off = (j - st) * nx;

        for (int i = 0; i < nx; i++) {
            ASSERT_EQ(h_in[i + in_off], h_out[i + out_off])
                << "at (" << i << "," << j << ")";
        }
    }

    delete[] h_in;
    delete[] h_out;
}
#endif
<commit_msg>TEST: Adding back commented out tests from flip<commit_after>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <gtest/gtest.h>
#include <af/array.h>
#include <af/arith.h>
#include <af/data.h>
#include <af/index.h>
#include <testHelpers.hpp>

using namespace std;
using namespace af;

TEST(FlipTests, Test_flip_1D)
{
    const int num = 10000;
    af::array in = randu(num);
    af::array out = flip(in, 0);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int i = 0; i < num; i++) {
        ASSERT_EQ(h_in[num - i - 1], h_out[i])
            << "at (" << i << ")";
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_2D0)
{
    const int nx = 200;
    const int ny = 200;

    af::array in = randu(nx, ny);
    af::array out = flip(in, 0);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int j = 0; j < ny; j++) {
        int off = j * nx;
        for (int i = 0; i < nx; i++) {
            ASSERT_EQ(h_in[off + nx - 1 - i], h_out[off + i])
                << "at (" << i << "," << j << ")";

        }
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_2D1)
{
    const int nx = 200;
    const int ny = 200;

    af::array in = randu(nx, ny);
    af::array out = flip(in, 1);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int j = 0; j < ny; j++) {
        int ioff = (ny - 1 - j) * nx;
        int ooff = j * nx;
        for (int i = 0; i < nx; i++) {
            ASSERT_EQ(h_in[ioff + i], h_out[ooff + i])
                << "at (" << i << "," << j << ")";
        }
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_1D_index)
{
    const int num = 10000;
    const int st = 101;
    const int en = 5000;

    af::array in = randu(num);
    af::array tmp = in(seq(st, en));
    af::array out = flip(tmp, 0);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int i = st; i <= en; i++) {
        ASSERT_EQ(h_in[i], h_out[en - i])
            << "at (" << i << ")";
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_2D_index00)
{
    const int nx = 200;
    const int ny = 200;
    const int st = 21;
    const int en = 180;
    const int nxo = (en - st + 1);

    af::array in = randu(nx, ny);
    af::array tmp = in(seq(st, en), span);
    af::array out = flip(tmp, 0);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int j = 0; j < ny; j++) {
        const int in_off = j * nx;
        const int out_off =j * nxo;
        for (int i = st; i <= en; i++) {
            ASSERT_EQ(h_in[i + in_off], h_out[en - i + out_off])
                << "at (" << i << "," << j << ")";
        }
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_2D_index01)
{
    const int nx = 200;
    const int ny = 200;
    const int st = 21;
    const int en = 180;
    const int nxo = (en - st + 1);

    af::array in = randu(nx, ny);
    af::array tmp = in(seq(st, en), span);
    af::array out = flip(tmp, 1);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int j = 0; j < ny; j++) {
        const int in_off = (ny - 1 - j) * nx;
        const int out_off =j * nxo;
        for (int i = st; i <= en; i++) {
            ASSERT_EQ(h_in[i + in_off], h_out[i - st + out_off])
                << "at (" << i << "," << j << ")";
        }
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_2D_index10)
{
    const int nx = 200;
    const int ny = 200;
    const int st = 21;
    const int en = 180;

    af::array in = randu(nx, ny);
    af::array tmp = in(span, seq(st, en));
    af::array out = flip(tmp, 0);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int j = st; j <= en; j++) {

        const int in_off = j * nx;
        const int out_off = (j - st) * nx;

        for (int i = 0; i < nx; i++) {
            ASSERT_EQ(h_in[nx - 1 - i + in_off], h_out[i + out_off])
                << "at (" << i << "," << j << ")";
        }
    }

    delete[] h_in;
    delete[] h_out;
}

TEST(FlipTests, Test_flip_2D_index11)
{
    const int nx = 200;
    const int ny = 200;
    const int st = 21;
    const int en = 180;

    af::array in = randu(nx, ny);
    af::array tmp = in(span, seq(st, en));
    af::array out = flip(tmp, 1);

    float *h_in = in.host<float>();
    float *h_out = out.host<float>();

    for (int j = st; j <= en; j++) {

        const int in_off = j * nx;
        const int out_off = (en - j) * nx;

        for (int i = 0; i < nx; i++) {
            ASSERT_EQ(h_in[i + in_off], h_out[i + out_off])
                << "at (" << i << "," << j << ")";
        }
    }

    delete[] h_in;
    delete[] h_out;
}
<|endoftext|>


<commit_before>#include "medic/node.h"

using namespace MEDIC;

MdNode::MdNode() {}

MdNode::MdNode(MObject &obj)
{
    m_obj = obj;
    m_dg.setObject(obj);
    m_is_dag = false;

    if (obj.hasFn(MFn::kDagNode))
    {
        m_is_dag = true;
        m_dag.setObject(obj);
    }
}

MdNode::MdNode(std::string name)
{
    MSelectionList sel;
    sel.add(name.c_str());
    MObject obj;
    sel.getDependNode(0, obj);

    m_obj = obj;
    m_dg.setObject(obj);
    m_is_dag = false;

    if (obj.hasFn(MFn::kDagNode))
    {
        m_is_dag = true;
        m_dag.setObject(obj);
    }
}

MdNode::~MdNode() {}

bool MdNode::Match(MObject &obj)
{
    return (!obj.isNull() && obj.hasFn(MFn::kDependencyNode)) ? true : false;
}

MObject &MdNode::object()
{
    return m_obj;
}

std::string MdNode::name() const
{
    if (!isDag())
    {
        return (std::string)m_dg.name().asChar();
    }

    return (std::string)m_dag.partialPathName().asChar();
}

std::string MdNode::type() const
{
    return (std::string)m_dg.typeName().asChar();
}

bool MdNode::isDag() const
{
    return m_is_dag;
}

void MdNode::parents(MdNodeContainer *container) const
{
    if (isDag())
    {
        for (unsigned int i = 0; i < m_dag.parentCount(); ++i)
        {
            MObject po = m_dag.parent(i);
            container->append(new MdNode(po));
        }
    }
}

void MdNode::children(MdNodeContainer *container) const
{
    if (isDag())
    {
        for (unsigned int i = 0; i < m_dag.parentCount(); ++i)
        {
            MObject po = m_dag.child(i);
            container->append(new MdNode(po));
        }
    }
}

MFnDagNode &MdNode::dag()
{
    return m_dag;
}

MFnDependencyNode &MdNode::dg()
{
    return m_dg;
}

MDagPath MdNode::getPath() const
{
    if (!isDag())
    {
        return MDagPath();
    }

    MDagPath path;
    m_dag.getPath(path);

    return path;
}

MdNodeContainer::MdNodeContainer() {}

MdNodeContainer::~MdNodeContainer()
{
    clear();
}

bool MdNodeContainer::append(MdNode *n)
{
    if (std::find(m_nodes.begin(), m_nodes.end(), n) == m_nodes.end())
    {
        m_nodes.push_back(n);
        return true;
    }

    return false;
}

bool MdNodeContainer::remove(MdNode *n)
{
    NodePtrVec::iterator it = std::find(m_nodes.begin(), m_nodes.end(), n);
    if (it != m_nodes.end())
    {
        m_nodes.erase(it);
        delete (*it);
        return true;
    }

    return false;
}

void MdNodeContainer::clear()
{
    for (NodePtrVec::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
    {
        delete (*it);
    }

    m_nodes.clear();
}

size_t MdNodeContainer::size() const
{
    return m_nodes.size();
}

MdNodeIterator MdNodeContainer::iterator()
{
    return MdNodeIterator(this);
}

MdNodeIterator::MdNodeIterator() {}

MdNodeIterator::MdNodeIterator(MdNodeContainer *container)
{
    m_container = container;
    m_cur = m_container->m_nodes.begin();
}

MdNodeIterator::~MdNodeIterator() {}

MdNode *MdNodeIterator::next()
{
    return *(m_cur++);
}

bool MdNodeIterator::isDone()
{
    return (m_cur == m_container->m_nodes.end());
}

void MEDIC::GetNodes(MdNodeContainer *container)
{
    int i = 0;
    MItDependencyNodes it;
    while (!it.isDone())
    {
        std::cout << i << std::endl;

        MObject obj = it.thisNode();
        if (MdNode::Match(obj))
        {
            MFnDependencyNode dn(obj);
            if (!dn.isShared() && !dn.isDefaultNode() && dn.canBeWritten())
            {
                MdNode *n = new MdNode(obj);
                container->append(n);
            }
        }

        it.next();
    }
}
<commit_msg>delete cout<commit_after>#include "medic/node.h"

using namespace MEDIC;

MdNode::MdNode() {}

MdNode::MdNode(MObject &obj)
{
    m_obj = obj;
    m_dg.setObject(obj);
    m_is_dag = false;

    if (obj.hasFn(MFn::kDagNode))
    {
        m_is_dag = true;
        m_dag.setObject(obj);
    }
}

MdNode::MdNode(std::string name)
{
    MSelectionList sel;
    sel.add(name.c_str());
    MObject obj;
    sel.getDependNode(0, obj);

    m_obj = obj;
    m_dg.setObject(obj);
    m_is_dag = false;

    if (obj.hasFn(MFn::kDagNode))
    {
        m_is_dag = true;
        m_dag.setObject(obj);
    }
}

MdNode::~MdNode() {}

bool MdNode::Match(MObject &obj)
{
    return (!obj.isNull() && obj.hasFn(MFn::kDependencyNode)) ? true : false;
}

MObject &MdNode::object()
{
    return m_obj;
}

std::string MdNode::name() const
{
    if (!isDag())
    {
        return (std::string)m_dg.name().asChar();
    }

    return (std::string)m_dag.partialPathName().asChar();
}

std::string MdNode::type() const
{
    return (std::string)m_dg.typeName().asChar();
}

bool MdNode::isDag() const
{
    return m_is_dag;
}

void MdNode::parents(MdNodeContainer *container) const
{
    if (isDag())
    {
        for (unsigned int i = 0; i < m_dag.parentCount(); ++i)
        {
            MObject po = m_dag.parent(i);
            container->append(new MdNode(po));
        }
    }
}

void MdNode::children(MdNodeContainer *container) const
{
    if (isDag())
    {
        for (unsigned int i = 0; i < m_dag.parentCount(); ++i)
        {
            MObject po = m_dag.child(i);
            container->append(new MdNode(po));
        }
    }
}

MFnDagNode &MdNode::dag()
{
    return m_dag;
}

MFnDependencyNode &MdNode::dg()
{
    return m_dg;
}

MDagPath MdNode::getPath() const
{
    if (!isDag())
    {
        return MDagPath();
    }

    MDagPath path;
    m_dag.getPath(path);

    return path;
}

MdNodeContainer::MdNodeContainer() {}

MdNodeContainer::~MdNodeContainer()
{
    clear();
}

bool MdNodeContainer::append(MdNode *n)
{
    if (std::find(m_nodes.begin(), m_nodes.end(), n) == m_nodes.end())
    {
        m_nodes.push_back(n);
        return true;
    }

    return false;
}

bool MdNodeContainer::remove(MdNode *n)
{
    NodePtrVec::iterator it = std::find(m_nodes.begin(), m_nodes.end(), n);
    if (it != m_nodes.end())
    {
        m_nodes.erase(it);
        delete (*it);
        return true;
    }

    return false;
}

void MdNodeContainer::clear()
{
    for (NodePtrVec::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
    {
        delete (*it);
    }

    m_nodes.clear();
}

size_t MdNodeContainer::size() const
{
    return m_nodes.size();
}

MdNodeIterator MdNodeContainer::iterator()
{
    return MdNodeIterator(this);
}

MdNodeIterator::MdNodeIterator() {}

MdNodeIterator::MdNodeIterator(MdNodeContainer *container)
{
    m_container = container;
    m_cur = m_container->m_nodes.begin();
}

MdNodeIterator::~MdNodeIterator() {}

MdNode *MdNodeIterator::next()
{
    return *(m_cur++);
}

bool MdNodeIterator::isDone()
{
    return (m_cur == m_container->m_nodes.end());
}

void MEDIC::GetNodes(MdNodeContainer *container)
{
    MItDependencyNodes it;
    while (!it.isDone())
    {
        MObject obj = it.thisNode();
        if (MdNode::Match(obj))
        {
            MFnDependencyNode dn(obj);
            if (!dn.isShared() && !dn.isDefaultNode() && dn.canBeWritten())
            {
                MdNode *n = new MdNode(obj);
                container->append(n);
            }
        }

        it.next();
    }
}
<|endoftext|>


<commit_before>/* Copyright 2009 SPARTA, Inc., dba Cobham Analytic Solutions
 *
 * This file is part of WATCHER.
 *
 *     WATCHER is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     WATCHER is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with Watcher.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @file routeFeeder.cpp
 * @author Geoff Lawler <geoff.lawler@cobham.com>
 * @date 2009-07-15
 */
#include <stdio.h>
#include <sysexits.h> 	// portablish exit values.
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <string.h>
#include <assert.h>

#include <string>
#include <vector>

#include <libwatcher/client.h>                         // we are a client of the watcher.
#include <libwatcher/edgeMessage.h>         // we may send edgeMessages to the watcher.
#include <libwatcher/connectivityMessage.h> // we may send connectivityMessages to the watcher.
#include <logger.h>

using namespace std;
using namespace watcher;
using namespace watcher::event;

static const char *rcsid __attribute__ ((unused)) = "$Id: routingfeeder.c,v 1.0 2009/04/28 22:08:47 glawler Exp $";

// #define DEBUG 1

/* This is a feeder which polls the routing table,
 * and draws the routing algorithm's edges on the watcher
 *
 *  Copyright (C) 2006,2007,2008,2009 Sparta Inc.  Written by the NIP group, SRD, ISSO
 */

struct Route
{
    unsigned int dst;
    unsigned int nexthop;
    unsigned int mask;
    char iface[16];

    Route(int d, int n, int m, char i[16]) : dst(d), nexthop(n), mask(m) { memcpy(iface, i, sizeof(iface)); }
    Route(const Route &cpy) { dst=cpy.dst; nexthop=cpy.nexthop; mask=cpy.mask; memcpy(iface, cpy.iface, sizeof(iface)); }
    ~Route() { }
    ostream &operator<<(ostream &out) { return out << "dst: " << dst << " nexthop: " << nexthop << " mask: " << mask << " iface: " << (const char *)iface; }

};

bool operator==(const Route &a, const Route &b) {
    return a.dst==b.dst && a.nexthop==b.nexthop && a.mask==b.mask && !strncmp(a.iface, b.iface, sizeof(a.iface));
}

bool operator<(const Route &a, const Route &b) {
    return a.dst < b.dst;
}

typedef vector<Route> RouteList;

/*
   Iface   Destination     Gateway         Flags   RefCnt  Use     Metric  Mask       MTU      Window  IRTT
   eth0    7402A8C0        7C02A8C0        0007    0       0       0       FFFFFFFF   00       0
   eth0    7402A8C0        7202A8C0        0007    0       0       0       FFFFFFFF   00       0
   */

static void routeRead(unsigned int network, unsigned int netmask, RouteList &oneHopRoutes, RouteList &nextHopRoutes)
{
    TRACE_ENTER();

    FILE *fil;
    char line[1024];

    fil=fopen("/proc/net/route","r");
    while(fgets(line,sizeof(line)-1,fil))
    {
        char iface[16];
        int flags,refcnt,use,metric,mtu,window;
        unsigned int dst,nexthop,mask;
        int rc;

        rc=sscanf(line,"%s\t%x\t%x\t%d\t%d\t%d\t%d\t%x\t%o\t%d\n",iface,&dst,&nexthop,&flags,&refcnt,&use,&metric,&mask,&mtu,&window);

        if (rc==10 && (ntohl(dst)!=ntohl(network)) && ((ntohl(dst) & ntohl(netmask)) == ntohl(network))) {
            if (nexthop==0)
                nextHopRoutes.push_back(Route(dst, nexthop, mask, iface));
            else
                oneHopRoutes.push_back(Route(dst, nexthop, mask, iface));
        }
    }

    fclose(fil);

    TRACE_EXIT();
    return;
}

#if DEBUG
static void routeDump(const RouteList &r)
{
    TRACE_ENTER();

    if (r.size()) {
        for (RouteList::const_iterator i=r.begin(); i!=r.end(); i++) {
            ostringstream out;
            out << *i;
        }
        LOG_DEBUG("%s", out.str().c_str());
    }

    TRACE_EXIT();
}
#endif // DEBUG

typedef struct detector
{
    Client *watcherClientPtr;

    useconds_t reportperiod;		/* frequency to generate reports at */
    int reportnum;
    string iface;
    int routeedgewidth;
    Color onehopcolor;
    Color nexthopcolor;

    string nexthoplayer;
    string onehoplayer;

    int duration;			  /* Time to run (in seconds) or 0 to run until broken */

	struct in_addr filterNetwork;
	struct in_addr filterMask;
	struct in_addr localhost;

    RouteList prevNextHopRoutes;   /* The previous next hop list we saw. */
    RouteList prevOneHopRoutes;    /* the previous one hop list we saw. */

    bool constantUpdates;

} detector;

typedef struct DetectorInit
{
    useconds_t reportperiod;		/* frequency to generate reports at */
    string iface;
    int onehopfamily;
    Color onehopcolor;
    Color nexthopcolor;
    int mouthnum;
    int duration;			  /* Time to run (in seconds) or 0 to run until broken */
    int routeedgewidth;

    string serverName;

    string nexthoplayer;
    string onehoplayer;

    bool constantUpdates;

	struct in_addr filterNetwork;
	struct in_addr filterMask;
	struct in_addr localhost;

} DetectorInit;

static void updateRoutes(detector *st, RouteList &oneHopRoutes, RouteList &nextHopRoutes)
{
    TRACE_ENTER();

    static vector<MessagePtr> messages;
    if(!messages.empty())
        messages.clear();

    bool sendMessage=false;

    /*
     * If constant updates is true, always send route list. Else only send when the new list differs from the old.
     */
    if (st->constantUpdates || oneHopRoutes!=st->prevOneHopRoutes) {
        ConnectivityMessagePtr message(new ConnectivityMessage);
        message->layer=ONE_HOP_ROUTING_LAYER;
        for (RouteList::const_iterator i=oneHopRoutes.begin(); i!=oneHopRoutes.end(); i++)
            if (st->iface != string(i->iface))
                message->neighbors.push_back(boost::asio::ip::address_v4(i->dst));
        st->prevOneHopRoutes=oneHopRoutes;
        messages.push_back(message);
        sendMessage=true;
    }
    if (st->constantUpdates || nextHopRoutes!=st->prevNextHopRoutes) {
        ConnectivityMessagePtr message(new ConnectivityMessage);
        message->layer=ROUTING_LAYER;
        for (RouteList::const_iterator i=nextHopRoutes.begin(); i!=nextHopRoutes.end(); i++)
            if (st->iface != string(i->iface))
                message->neighbors.push_back(boost::asio::ip::address_v4(i->nexthop));
        st->prevNextHopRoutes=nextHopRoutes;
        messages.push_back(message);
        sendMessage=true;
    }

    if (sendMessage)
        st->watcherClientPtr->sendMessages(messages);

    TRACE_EXIT();
}

/* This is called regularly by the select loop (below)
 * It will create a message, and send it to this node's coordinator
 */
static void detectorSend(detector *st)
{
    TRACE_ENTER();

    RouteList oneHopRoutes, nextHopRoutes;

    routeRead(st->filterNetwork.s_addr, st->filterMask.s_addr, oneHopRoutes, nextHopRoutes);

    long long int curtime;
    struct timeval tp;
    gettimeofday(&tp, NULL);
    curtime=(long long int)tp.tv_sec*1000 + (long long int)tp.tv_usec/1000;

    LOG_DEBUG("node= " << st->localhost.s_addr << " time= " << curtime << " routes= " << nextHopRoutes.size() << " onehoproutes= " << oneHopRoutes.size() << " totalroutes= " << nextHopRoutes.size()+oneHopRoutes.size());

    st->reportnum++;

    updateRoutes(st,oneHopRoutes, nextHopRoutes);

    TRACE_EXIT();
}

static detector *detectorInit(DetectorInit *detinit)
{
    TRACE_ENTER();
    detector *st;

    st=new detector;
    st->iface="";

    st->watcherClientPtr=new Client(detinit->serverName);
    if(st->watcherClientPtr==NULL)
        return NULL;

    st->duration=detinit->duration;
    st->constantUpdates=detinit->constantUpdates;
    st->reportperiod=detinit->reportperiod;
    st->reportnum=0;
    st->iface=detinit->iface;

    st->onehoplayer=detinit->onehoplayer;
    st->onehopcolor=detinit->onehopcolor;

    st->nexthoplayer=detinit->nexthoplayer;
    st->nexthopcolor=st->nexthopcolor;

    st->routeedgewidth=detinit->routeedgewidth;

	st->filterNetwork.s_addr=detinit->filterNetwork.s_addr;
	st->filterMask.s_addr=detinit->filterMask.s_addr;
	st->localhost.s_addr=detinit->localhost.s_addr;

    TRACE_EXIT();
    return st;
}

/*
 * Wait around until we are ready to generate a message, then do it.
 */
static void selectLoop(detector *dt)
{
    TRACE_ENTER();

    time_t startTime=time(NULL);

    while(1)
    {
        usleep(dt->reportperiod*(useconds_t)1000.0);
        detectorSend(dt);

        if (dt->duration)
            if (time(NULL)-startTime>dt->duration)
                break;
    }

    dt->watcherClientPtr->wait();

    TRACE_EXIT();
}

int main(int argc, char *argv[])
{
    TRACE_ENTER();
    detector *dt;
    int ch;
    string logPropsFile("routeFeeder.log.properties");

    DetectorInit detinit;
    detinit.iface="";
    detinit.onehopcolor=Color::green;
    detinit.onehoplayer="One Hop Routing";
    detinit.nexthopcolor=Color::blue;
    detinit.nexthoplayer="Network Routing";
    detinit.reportperiod=2000;
    detinit.duration=0;
    detinit.routeedgewidth=15;

	detinit.filterNetwork.s_addr=0;
	detinit.filterMask.s_addr=0;
	detinit.localhost.s_addr=0;

    while ((ch = getopt(argc, argv, "m:n:h:o:x:t:e:b:i:d:p:w:l:c?")) != -1)
        switch (ch)
        {
            case 'm': if(-1 == inet_pton(AF_INET, optarg, &detinit.filterMask))
                      {
                          fprintf(stderr, "Error parsing filter mask: %s\n", optarg);
                          exit(EX_USAGE);
                      }
                      break;
            case 'n': if(-1 == inet_pton(AF_INET, optarg, &detinit.filterNetwork))
                      {
                          fprintf(stderr, "Error parsing filter network: %s\n", optarg);
                          exit(EX_USAGE);
                      }
                      break;
            case 'h': if(-1 == inet_pton(AF_INET, optarg, &detinit.localhost))
                      {
                          fprintf(stderr, "Error parsing localhost address: %s\n", optarg);
                          exit(EX_USAGE);
                      }
                      break;
            case 'o':
                      detinit.onehopcolor.fromString(optarg);
                      break;
            case 'x':
                      detinit.nexthopcolor.fromString(optarg);
                      break;
            case 't':
                      sscanf(optarg,"%d",&detinit.duration);
                      break;
            case 'e':
                      detinit.onehoplayer=string(optarg);
                      break;
            case 'b':
                      detinit.nexthoplayer=string(optarg);
                      break;
            case 'i':
                      detinit.iface=string(optarg);
                      break;
            case 'd':
                      detinit.serverName=string(optarg);
                      break;
            case 'p':
                      sscanf(optarg,"%d",&detinit.reportperiod);
                      break;
            case 'w':
                      sscanf(optarg, "%d", &detinit.routeedgewidth);
                      break;
            case 'l':
                      logPropsFile=string(optarg);
                      break;
            case 'u':
                      detinit.constantUpdates=true;
                      break;
            case '?':
            default:
                      fprintf(stderr,"%s - poll the linux routing table, and draw the routes in the watcher\n"
                              "-d ipaddr/hostname - specify watcherd address to connect to (duck)\n"
                              "-h ipaddr - this host's address\n"
                              "-m netmask - the mask used to filter the routes (ex. 255.255.255.0)\n"
                              "-n network - the network used to filter the routes (ex. 192.168.1.0)\n"
                              "-p milliseconds - specify the period to poll and report\n"
                              "-i interface - display only routes through this ethernet interface (or any if unspecified)\n"
                              "-e layer - onehop layer name\n"
                              "-b layer - nexthop layer name\n"
                              "-t seconds - Run for this long, then exit\n"
                              "-u - send updates every period. If not set, only send updates when the routes change.\n",
                              // "-c - use connectivity messages instead of edge messages (this disables width and color settings)\n"
                              basename(argv[0])
                             );
                      exit(1);
                      break;
        }

    // init the logging system
    LOAD_LOG_PROPS(logPropsFile);
    LOG_INFO("Logger initialized from file \"" << logPropsFile << "\"");

	// check args, errors, etc before doing real work
	if(detinit.localhost.s_addr == 0)
    {
        fprintf(stderr, "localhost address cannot be blank\n");
        exit(EX_USAGE);
    }
	if(detinit.filterNetwork.s_addr == 0)
	{
        fprintf(stderr, "filter network cannot be blank\n");
        exit(EX_USAGE);
	}
	if(detinit.filterMask.s_addr == 0)
	{
        fprintf(stderr, "filter mask cannot be blank\n");
        exit(EX_USAGE);
	}
	if(detinit.serverName.empty())
	{
        fprintf(stderr, "watcherd hostname cannot be blank\n");
        exit(EX_USAGE);
	}

    dt=detectorInit(&detinit);

    if (dt==NULL)
    {
        fprintf(stderr,"detector init failed, probably could not connect to infrastructure demon.\n");
        exit(1);
    }
    printf("%s: starting\n",argv[0]);
    selectLoop(dt);

    TRACE_EXIT();
    return 0;
}
<commit_msg>routeFeeder: small updates/fixes.<commit_after>/* Copyright 2009 SPARTA, Inc., dba Cobham Analytic Solutions
 *
 * This file is part of WATCHER.
 *
 *     WATCHER is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     WATCHER is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with Watcher.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @file routeFeeder.cpp
 * @author Geoff Lawler <geoff.lawler@cobham.com>
 * @date 2009-07-15
 */
#include <stdio.h>
#include <sysexits.h> 	// portablish exit values.
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <string.h>
#include <assert.h>

#include <string>
#include <vector>

#include <libwatcher/client.h>                         // we are a client of the watcher.
#include <libwatcher/edgeMessage.h>         // we may send edgeMessages to the watcher.
#include <libwatcher/connectivityMessage.h> // we may send connectivityMessages to the watcher.
#include <logger.h>

using namespace std;
using namespace watcher;
using namespace watcher::event;

static const char *rcsid __attribute__ ((unused)) = "$Id: routingfeeder.c,v 1.0 2009/04/28 22:08:47 glawler Exp $";

// #define DEBUG 1

/* This is a feeder which polls the routing table,
 * and draws the routing algorithm's edges on the watcher
 *
 *  Copyright (C) 2006,2007,2008,2009 Sparta Inc.  Written by the NIP group, SRD, ISSO
 */

struct Route
{
    unsigned int dst;
    unsigned int nexthop;
    unsigned int mask;
    char iface[16];

    Route(int d, int n, int m, char i[16]) : dst(d), nexthop(n), mask(m) { memcpy(iface, i, sizeof(iface)); }
    Route(const Route &cpy) { dst=cpy.dst; nexthop=cpy.nexthop; mask=cpy.mask; memcpy(iface, cpy.iface, sizeof(iface)); }
    ~Route() { }
    ostream &operator<<(ostream &out) { return out << "dst: " << dst << " nexthop: " << nexthop << " mask: " << mask << " iface: " << (const char *)iface; }

};

bool operator==(const Route &a, const Route &b) {
    return a.dst==b.dst && a.nexthop==b.nexthop && a.mask==b.mask && !strncmp(a.iface, b.iface, sizeof(a.iface));
}

bool operator<(const Route &a, const Route &b) {
    return a.dst < b.dst;
}

typedef vector<Route> RouteList;

#if DEBUG
static void routeDump(const RouteList &r)
{
    TRACE_ENTER();

    if (r.size()) {
        for (RouteList::const_iterator i=r.begin(); i!=r.end(); i++) {
            ostringstream out;
            out << *i;
        }
        LOG_DEBUG("%s", out.str().c_str());
    }

    TRACE_EXIT();
}
#endif // DEBUG

typedef struct detector
{
    Client *watcherClientPtr;

    useconds_t reportperiod;		/* frequency to generate reports at */
    int reportnum;
    string iface;
    int routeedgewidth;
    Color onehopcolor;
    Color nexthopcolor;

    string nexthoplayer;
    string onehoplayer;

    int duration;			  /* Time to run (in seconds) or 0 to run until broken */

	struct in_addr filterNetwork;
	struct in_addr filterMask;
	struct in_addr localhost;

    RouteList prevNextHopRoutes;   /* The previous next hop list we saw. */
    RouteList prevOneHopRoutes;    /* the previous one hop list we saw. */

    bool constantUpdates;

} detector;

typedef struct DetectorInit
{
    useconds_t reportperiod;		/* frequency to generate reports at */
    string iface;
    int onehopfamily;
    Color onehopcolor;
    Color nexthopcolor;
    int mouthnum;
    int duration;			  /* Time to run (in seconds) or 0 to run until broken */
    int routeedgewidth;

    string serverName;

    string nexthoplayer;
    string onehoplayer;

    bool constantUpdates;

	struct in_addr filterNetwork;
	struct in_addr filterMask;
	struct in_addr localhost;

} DetectorInit;

/*
   Iface   Destination     Gateway         Flags   RefCnt  Use     Metric  Mask       MTU      Window  IRTT
   eth0    7402A8C0        7C02A8C0        0007    0       0       0       FFFFFFFF   00       0
   eth0    7402A8C0        7202A8C0        0007    0       0       0       FFFFFFFF   00       0
   */
static void routeRead(unsigned int network, unsigned int netmask, RouteList &oneHopRoutes, RouteList &nextHopRoutes)
{
    TRACE_ENTER();

    FILE *fil;
    char line[1024];

    fil=fopen("/proc/net/route","r");
    while(fgets(line,sizeof(line)-1,fil))
    {
        char iface[16];
        int flags,refcnt,use,metric,mtu,window;
        unsigned int dst,nexthop,mask;
        int rc;

        rc=sscanf(line,"%s\t%x\t%x\t%d\t%d\t%d\t%d\t%x\t%o\t%d\n",iface,&dst,&nexthop,&flags,&refcnt,&use,&metric,&mask,&mtu,&window);

        if (rc==10 && (ntohl(dst)!=ntohl(network)) && ((ntohl(dst) & ntohl(netmask)) == ntohl(network))) {
            if (nexthop!=0)
                nextHopRoutes.push_back(Route(ntohl(dst), ntohl(nexthop), ntohl(mask), iface));
            else
                oneHopRoutes.push_back(Route(ntohl(dst), ntohl(nexthop), ntohl(mask), iface));
        }
    }

    fclose(fil);

    TRACE_EXIT();
    return;
}

static void updateRoutes(detector *st, RouteList &oneHopRoutes, RouteList &nextHopRoutes)
{
    TRACE_ENTER();

    static vector<MessagePtr> messages;
    if(!messages.empty())
        messages.clear();

    bool sendMessage=false;

    /*
     * If constant updates is true, always send route list. Else only send when the new list differs from the old.
     */
    if (st->constantUpdates || oneHopRoutes!=st->prevOneHopRoutes) {
        ConnectivityMessagePtr message(new ConnectivityMessage);
        message->layer=ONE_HOP_ROUTING_LAYER;
        for (RouteList::const_iterator i=oneHopRoutes.begin(); i!=oneHopRoutes.end(); i++)
            if (st->iface != string(i->iface))
                message->neighbors.push_back(boost::asio::ip::address_v4(i->dst));
        st->prevOneHopRoutes=oneHopRoutes;
        messages.push_back(message);
        sendMessage=true;
    }
    if (st->constantUpdates || nextHopRoutes!=st->prevNextHopRoutes) {
        ConnectivityMessagePtr message(new ConnectivityMessage);
        message->layer=ROUTING_LAYER;
        for (RouteList::const_iterator i=nextHopRoutes.begin(); i!=nextHopRoutes.end(); i++)
            if (st->iface != string(i->iface))
                message->neighbors.push_back(boost::asio::ip::address_v4(i->nexthop));
        st->prevNextHopRoutes=nextHopRoutes;
        messages.push_back(message);
        sendMessage=true;
    }

    if (sendMessage)
        st->watcherClientPtr->sendMessages(messages);

    TRACE_EXIT();
}

/* This is called regularly by the select loop (below)
 * It will create a message, and send it to this node's coordinator
 */
static void detectorSend(detector *st)
{
    TRACE_ENTER();

    RouteList oneHopRoutes, nextHopRoutes;

    routeRead(st->filterNetwork.s_addr, st->filterMask.s_addr, oneHopRoutes, nextHopRoutes);

    long long int curtime;
    struct timeval tp;
    gettimeofday(&tp, NULL);
    curtime=(long long int)tp.tv_sec*1000 + (long long int)tp.tv_usec/1000;

    LOG_DEBUG("node= " << st->localhost.s_addr << " time= " << curtime << " routes= " << nextHopRoutes.size() << " onehoproutes= " << oneHopRoutes.size() << " totalroutes= " << nextHopRoutes.size()+oneHopRoutes.size());

    st->reportnum++;

    updateRoutes(st,oneHopRoutes, nextHopRoutes);

    TRACE_EXIT();
}

static detector *detectorInit(DetectorInit *detinit)
{
    TRACE_ENTER();
    detector *st;

    st=new detector;
    st->iface="";

    st->watcherClientPtr=new Client(detinit->serverName);
    if(st->watcherClientPtr==NULL)
        return NULL;

    st->duration=detinit->duration;
    st->constantUpdates=detinit->constantUpdates;
    st->reportperiod=detinit->reportperiod;
    st->reportnum=0;
    st->iface=detinit->iface;

    st->onehoplayer=detinit->onehoplayer;
    st->onehopcolor=detinit->onehopcolor;

    st->nexthoplayer=detinit->nexthoplayer;
    st->nexthopcolor=st->nexthopcolor;

    st->routeedgewidth=detinit->routeedgewidth;

	st->filterNetwork.s_addr=detinit->filterNetwork.s_addr;
	st->filterMask.s_addr=detinit->filterMask.s_addr;
	st->localhost.s_addr=detinit->localhost.s_addr;

    TRACE_EXIT();
    return st;
}

/*
 * Wait around until we are ready to generate a message, then do it.
 */
static void selectLoop(detector *dt)
{
    TRACE_ENTER();

    time_t startTime=time(NULL);

    while(1)
    {
        usleep(dt->reportperiod*(useconds_t)1000.0);
        detectorSend(dt);

        if (dt->duration)
            if (time(NULL)-startTime>dt->duration)
                break;
    }

    dt->watcherClientPtr->wait();

    TRACE_EXIT();
}

int main(int argc, char *argv[])
{
    TRACE_ENTER();
    detector *dt;
    int ch;
    string logPropsFile("routeFeeder.log.properties");

    DetectorInit detinit;
    detinit.iface="";
    detinit.onehopcolor=Color::green;
    detinit.onehoplayer="One Hop Routing";
    detinit.nexthopcolor=Color::blue;
    detinit.nexthoplayer="Network Routing";
    detinit.reportperiod=2000;
    detinit.duration=0;
    detinit.routeedgewidth=15;

	detinit.filterNetwork.s_addr=0;
	detinit.filterMask.s_addr=0;
	detinit.localhost.s_addr=0;

    detinit.constantUpdates=false;

    while ((ch = getopt(argc, argv, "m:n:h:o:x:t:e:b:i:d:p:w:l:cu?")) != -1)
        switch (ch)
        {
            case 'm': if(-1 == inet_pton(AF_INET, optarg, &detinit.filterMask))
                      {
                          fprintf(stderr, "Error parsing filter mask: %s\n", optarg);
                          exit(EX_USAGE);
                      }
                      break;
            case 'n': if(-1 == inet_pton(AF_INET, optarg, &detinit.filterNetwork))
                      {
                          fprintf(stderr, "Error parsing filter network: %s\n", optarg);
                          exit(EX_USAGE);
                      }
                      break;
            case 'h': if(-1 == inet_pton(AF_INET, optarg, &detinit.localhost))
                      {
                          fprintf(stderr, "Error parsing localhost address: %s\n", optarg);
                          exit(EX_USAGE);
                      }
                      break;
            case 'o':
                      detinit.onehopcolor.fromString(optarg);
                      break;
            case 'x':
                      detinit.nexthopcolor.fromString(optarg);
                      break;
            case 't':
                      sscanf(optarg,"%d",&detinit.duration);
                      break;
            case 'e':
                      detinit.onehoplayer=string(optarg);
                      break;
            case 'b':
                      detinit.nexthoplayer=string(optarg);
                      break;
            case 'i':
                      detinit.iface=string(optarg);
                      break;
            case 'd':
                      detinit.serverName=string(optarg);
                      break;
            case 'p':
                      sscanf(optarg,"%d",&detinit.reportperiod);
                      break;
            case 'w':
                      sscanf(optarg, "%d", &detinit.routeedgewidth);
                      break;
            case 'l':
                      logPropsFile=string(optarg);
                      break;
            case 'u':
                      detinit.constantUpdates=true;
                      break;
            case '?':
            default:
                      fprintf(stderr,"%s - poll the linux routing table, and draw the routes in the watcher\n"
                              "-d ipaddr/hostname - specify watcherd address to connect to (duck)\n"
                              "-h ipaddr - this host's address\n"
                              "-m netmask - the mask used to filter the routes (ex. 255.255.255.0)\n"
                              "-n network - the network used to filter the routes (ex. 192.168.1.0)\n"
                              "-p milliseconds - specify the period to poll and report\n"
                              "-i interface - display only routes through this ethernet interface (or any if unspecified)\n"
                              "-e layer - onehop layer name\n"
                              "-b layer - nexthop layer name\n"
                              "-t seconds - Run for this long, then exit\n"
                              "-u - send updates every period. If not set, only send updates when the routes change.\n",
                              // "-c - use connectivity messages instead of edge messages (this disables width and color settings)\n"
                              basename(argv[0])
                             );
                      exit(1);
                      break;
        }

    // init the logging system
    LOAD_LOG_PROPS(logPropsFile);
    LOG_INFO("Logger initialized from file \"" << logPropsFile << "\"");

	// check args, errors, etc before doing real work
	if(detinit.localhost.s_addr == 0)
    {
        fprintf(stderr, "localhost address cannot be blank\n");
        exit(EX_USAGE);
    }
	if(detinit.filterNetwork.s_addr == 0)
	{
        fprintf(stderr, "filter network cannot be blank\n");
        exit(EX_USAGE);
	}
	if(detinit.filterMask.s_addr == 0)
	{
        fprintf(stderr, "filter mask cannot be blank\n");
        exit(EX_USAGE);
	}
	if(detinit.serverName.empty())
	{
        fprintf(stderr, "watcherd hostname cannot be blank\n");
        exit(EX_USAGE);
	}

    dt=detectorInit(&detinit);

    if (dt==NULL)
    {
        fprintf(stderr,"detector init failed, probably could not connect to infrastructure demon.\n");
        exit(1);
    }
    printf("%s: starting\n",argv[0]);
    selectLoop(dt);

    TRACE_EXIT();
    return 0;
}
<|endoftext|>


<commit_before>#include <assert.h>
#include <limits.h>
#include <stdlib.h>

#include <algorithm>
#include <sstream>
#include <vector>

#include <leveldb/db.h>
#include <node.h>
#include <node_buffer.h>
#include <v8.h>

#include "batch.h"
#include "handle.h"
#include "helpers.h"
#include "iterator.h"
#include "options.h"

using namespace node;
using namespace v8;

namespace node_leveldb {

Persistent<FunctionTemplate> JHandle::constructor;

static inline Handle<Value> Error(const leveldb::Status& status) {
  if (status.IsNotFound()) {
    return Undefined();
  } else {
    return ThrowError(status.ToString().c_str());
  }
}

void JHandle::Initialize(Handle<Object> target) {
  HandleScope scope;

  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  constructor = Persistent<FunctionTemplate>::New(t);
  constructor->InstanceTemplate()->SetInternalFieldCount(1);
  constructor->SetClassName(String::NewSymbol("Handle"));

  // Instance methods
  NODE_SET_PROTOTYPE_METHOD(constructor, "get", Read);
  NODE_SET_PROTOTYPE_METHOD(constructor, "write", Write);
  NODE_SET_PROTOTYPE_METHOD(constructor, "iterator", Iterator);
  NODE_SET_PROTOTYPE_METHOD(constructor, "snapshot", Snapshot);
  NODE_SET_PROTOTYPE_METHOD(constructor, "property", Property);
  NODE_SET_PROTOTYPE_METHOD(constructor, "approximateSizes", ApproximateSizes);
  NODE_SET_PROTOTYPE_METHOD(constructor, "compactRange", CompactRange);

  // Static methods
  NODE_SET_METHOD(target, "open", Open);
  NODE_SET_METHOD(target, "destroy", Destroy);
  NODE_SET_METHOD(target, "repair", Repair);

  // Set version
  std::stringstream version;
  version << leveldb::kMajorVersion << "." << leveldb::kMinorVersion;
  target->Set(String::New("bindingVersion"),
              String::New(version.str().c_str()),
              static_cast<PropertyAttribute>(ReadOnly|DontDelete));
}

Handle<Value> JHandle::New(const Arguments& args) {
  HandleScope scope;

  assert(args.Length() == 2);
  assert(args[0]->IsExternal());

  leveldb::DB* db = (leveldb::DB*)External::Unwrap(args[0]);
  JHandle* self = new JHandle(db);

  if (args[1]->IsExternal())
    self->comparator_ = Persistent<Value>::New(args[1]);

  self->Wrap(args.This());

  return args.This();
}

/**

    Open

 */

typedef struct open_params {
  std::string name_;

  leveldb::Options options_;
  leveldb::Status status_;
  leveldb::DB* db_;

  Persistent<Value> comparator_;
  Persistent<Function> callback_;

  virtual ~open_params() {
    comparator_.Dispose();
    callback_.Dispose();
  }
} open_params_t;

static void AsyncOpen(uv_work_t* req) {
  open_params_t* op = static_cast<open_params_t*>(req->data);
  op->status_ = leveldb::DB::Open(op->options_, op->name_, &op->db_);
}

static void AfterOpen(uv_work_t* req) {
  HandleScope scope;
  open_params_t* op = static_cast<open_params_t*>(req->data);
  assert(!op->callback_.IsEmpty());

  Handle<Value> error = Null();
  Handle<Value> result = Undefined();

  if (op->status_.ok()) {
    Handle<Value> args[] = { External::New(op->db_), Undefined() };
    if (!op->comparator_.IsEmpty()) args[1] = op->comparator_;
    result = JHandle::constructor->GetFunction()->NewInstance(2, args);
  } else {
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
  }

  Handle<Value> argv[] = { error, result };

  TryCatch tryCatch;
  op->callback_->Call(Context::GetCurrent()->Global(), 2, argv);
  if (tryCatch.HasCaught()) FatalException(tryCatch);

  delete op;
  delete req;
}

Handle<Value> JHandle::Open(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 3 ||
      !args[0]->IsString() ||
      !args[2]->IsFunction())
    return ThrowTypeError("Invalid arguments");

  open_params_t* op = new open_params_t;

  // Required filename
  op->name_ = *String::Utf8Value(args[0]);

  // Required callback
  op->callback_ = Persistent<Function>::New(Local<Function>::Cast(args[2]));

  // Optional options
  UnpackOptions(args[1], op->options_, &op->comparator_);

  AsyncQueue(op, AsyncOpen, AfterOpen);

  return Undefined();
}

/**

    Destroy

 */

Handle<Value> JHandle::Destroy(const Arguments& args) {
  HandleScope scope;

  if (args.Length() < 1 || !args[0]->IsString())
    return ThrowTypeError("Invalid arguments");

  OpenOp* op = OpenOp::New(Destroy, OpenConv, args);
  op->name_ = *String::Utf8Value(args[0]);

  // Optional options
  if (args.Length() > 1) UnpackOptions(args[1], op->options_);

  return op->Run();
}

void JHandle::Destroy(OpenOp* op) {
  op->status_ = leveldb::DestroyDB(op->name_, op->options_);
}

/**

    Repair

 */

Handle<Value> JHandle::Repair(const Arguments& args) {
  HandleScope scope;

  if (args.Length() < 1 || !args[0]->IsString())
    return ThrowTypeError("Invalid arguments");

  OpenOp* op = OpenOp::New(Repair, OpenConv, args);
  op->name_ = *String::Utf8Value(args[0]);

  // Optional options
  if (args.Length() > 1) UnpackOptions(args[1], op->options_);

  return op->Run();
}

Handle<Value> JHandle::Read(const Arguments& args) {
  HandleScope scope;

  int argc = args.Length();
  if (argc < 1 || !Buffer::HasInstance(args[0]))
    return ThrowTypeError("Invalid arguments");

  ReadOp* op = ReadOp::New(Read, Read, args);
  op->key_ = ToSlice(args[0], op->keyHandle_);

  // Optional read options
  if (argc > 1) UnpackReadOptions(args[1], op->options_);

  return op->Run();
}

Handle<Value> JHandle::Write(const Arguments& args) {
  HandleScope scope;

  int argc = args.Length();
  if (argc < 1 || !JBatch::HasInstance(args[0]))
    return ThrowTypeError("Invalid arguments");

  WriteOp* op = WriteOp::New(Write, Write, args);
  op->batch_ = ObjectWrap::Unwrap<JBatch>(args[0]->ToObject());

  // Optional write options
  if (argc > 1) UnpackWriteOptions(args[1], op->options_);

  return op->Run();
}

Handle<Value> JHandle::RefIterator(leveldb::Iterator* it) {
  Local<Value> argv[] = { External::New(it) };
  Local<Object> instance = JIterator::constructor->GetFunction()->NewInstance(1, argv);

  // Keep a weak reference
  Persistent<Object> weak = Persistent<Object>::New(instance);
  weak.MakeWeak(this, &UnrefIterator);

  Ref();

  return instance;
}

void JHandle::UnrefIterator(Persistent<Value> object, void* parameter) {
  assert(object->IsObject());

  JHandle* self = static_cast<JHandle*>(parameter);
  assert(self);

  self->Unref();
  object.Dispose();
}

Handle<Value> JHandle::Iterator(const Arguments& args) {
  HandleScope scope;
  IteratorOp* op = IteratorOp::New(Iterator, Iterator, args);
  if (args.Length() > 0) UnpackReadOptions(args[0], op->options_);
  return op->Run();
}

Handle<Value> JHandle::RefSnapshot(const leveldb::Snapshot* snapshot) {
  Local<Value> instance = External::New((void*)snapshot);
  Persistent<Value> weak = Persistent<Value>::New(instance);
  weak.MakeWeak(this, &UnrefSnapshot);
  Ref();
  return instance;
}

void JHandle::UnrefSnapshot(Persistent<Value> object, void* parameter) {
  assert(object->IsExternal());

  JHandle* self = static_cast<JHandle*>(parameter);
  leveldb::Snapshot* snapshot =
    static_cast<leveldb::Snapshot*>(External::Unwrap(object));

  assert(self);
  assert(snapshot);

  self->db_->ReleaseSnapshot(snapshot);
  self->Unref();

  object.Dispose();
}

Handle<Value> JHandle::Snapshot(const Arguments& args) {
  HandleScope scope;
  return SnapshotOp::Go(Snapshot, Snapshot, args);
}

Handle<Value> JHandle::Property(const Arguments& args) {
  HandleScope scope;

  if (args.Length() < 1 || !args[0]->IsString())
    return ThrowTypeError("Invalid arguments");

  PropertyOp* op = PropertyOp::New(Property, Property, args);
  op->name_ = *String::Utf8Value(args[0]);

  return op->Run();
}

Handle<Value> JHandle::ApproximateSizes(const Arguments& args) {
  HandleScope scope;

  if (args.Length() < 1 || !args[0]->IsArray())
    return ThrowTypeError("Invalid arguments");

  Local<Array> array(Array::Cast(*args[0]));

  int len = array->Length();
  if (len % 2 != 0)
    return ThrowTypeError("Invalid arguments");

  ApproximateSizesOp* op =
    ApproximateSizesOp::New(ApproximateSizes, ApproximateSizes, args);

  for (int i = 0; i < len; i += 2) {
    if (array->Has(i) && array->Has(i + 1)) {
      Local<Value> lStart = array->Get(i);
      Local<Value> lLimit = array->Get(i + 1);

      leveldb::Slice start = ToSlice(lStart, op->handles_);
      leveldb::Slice limit = ToSlice(lLimit, op->handles_);

      op->ranges_.push_back(leveldb::Range(start, limit));
    }
  }

  return op->Run();
}

Handle<Value> JHandle::CompactRange(const Arguments& args) {
  HandleScope scope;
  return ThrowError("Method not implemented");
}

//
// ASYNC FUNCTIONS
//

void JHandle::Repair(OpenOp* op) {
  op->status_ = leveldb::RepairDB(op->name_, op->options_);
}

void JHandle::OpenConv(OpenOp* op, Handle<Value>& error, Handle<Value>& result) {
  if (!op->status_.ok())
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
}

void JHandle::Read(ReadOp* op) {
  op->result_ = new std::string;
  op->status_ = op->self_->db_->Get(op->options_, op->key_, op->result_);
}

void JHandle::Read(ReadOp* op, Handle<Value>& error, Handle<Value>& result) {
  if (op->status_.ok()) {
    result = ToBuffer(op->result_);
  } else if (!op->status_.IsNotFound()) {
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
  }
}

void JHandle::Write(WriteOp* op) {
  op->batch_->ReadLock();
  op->status_ = op->self_->db_->Write(op->options_, &op->batch_->wb_);
  op->batch_->ReadUnlock();
}

void JHandle::Write(WriteOp* op, Handle<Value>& error, Handle<Value>& result) {
  if (!op->status_.ok())
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
}

void JHandle::Iterator(IteratorOp* op) {
  op->it_ = op->self_->db_->NewIterator(op->options_);
}

void JHandle::Iterator(IteratorOp* op, Handle<Value>& error, Handle<Value>& result) {
  if (op->status_.ok()) {
    result = op->self_->RefIterator(op->it_);
  } else {
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
  }
}

void JHandle::Snapshot(SnapshotOp* op) {
  op->snap_ = const_cast<leveldb::Snapshot*>(op->self_->db_->GetSnapshot());
}

void JHandle::Snapshot(SnapshotOp* op, Handle<Value>& error, Handle<Value>& result) {
  if (op->status_.ok()) {
    result = op->self_->RefSnapshot(op->snap_);
  } else {
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
  }
}

void JHandle::Property(PropertyOp* op) {
  leveldb::Slice name(op->name_);
  op->hasProperty_ = op->self_->db_->GetProperty(name, &op->value_);
}

void JHandle::Property(PropertyOp* op, Handle<Value>& error, Handle<Value>& result) {
  if (op->hasProperty_) result = String::New(op->value_.c_str());
}

void JHandle::ApproximateSizes(ApproximateSizesOp* op) {
  int len = op->ranges_.size();
  op->sizes_ = new uint64_t[len];
  op->self_->db_->GetApproximateSizes(&op->ranges_[0], len, op->sizes_);
}

void JHandle::ApproximateSizes(ApproximateSizesOp* op,
                               Handle<Value>& error, Handle<Value>& result)
{
  int len = op->ranges_.size();

  Handle<Array> array = Array::New(len);

  for (int i = 0; i < len; ++i) {
    uint64_t size = op->sizes_[i];
    if (size < INT_MAX) {
      array->Set(i, Integer::New(static_cast<uint32_t>(size)));
    } else {
      array->Set(i, Number::New(static_cast<double>(size)));
    }
  }

  result = array;
}

} // namespace node_leveldb
<commit_msg>Drop async support for Handle::Destroy()<commit_after>#include <assert.h>
#include <limits.h>
#include <stdlib.h>

#include <algorithm>
#include <sstream>
#include <vector>

#include <leveldb/db.h>
#include <node.h>
#include <node_buffer.h>
#include <v8.h>

#include "batch.h"
#include "handle.h"
#include "helpers.h"
#include "iterator.h"
#include "options.h"

using namespace node;
using namespace v8;

namespace node_leveldb {

Persistent<FunctionTemplate> JHandle::constructor;

static inline Handle<Value> Error(const leveldb::Status& status) {
  if (status.IsNotFound()) {
    return Undefined();
  } else {
    return ThrowError(status.ToString().c_str());
  }
}

void JHandle::Initialize(Handle<Object> target) {
  HandleScope scope;

  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  constructor = Persistent<FunctionTemplate>::New(t);
  constructor->InstanceTemplate()->SetInternalFieldCount(1);
  constructor->SetClassName(String::NewSymbol("Handle"));

  // Instance methods
  NODE_SET_PROTOTYPE_METHOD(constructor, "get", Read);
  NODE_SET_PROTOTYPE_METHOD(constructor, "write", Write);
  NODE_SET_PROTOTYPE_METHOD(constructor, "iterator", Iterator);
  NODE_SET_PROTOTYPE_METHOD(constructor, "snapshot", Snapshot);
  NODE_SET_PROTOTYPE_METHOD(constructor, "property", Property);
  NODE_SET_PROTOTYPE_METHOD(constructor, "approximateSizes", ApproximateSizes);
  NODE_SET_PROTOTYPE_METHOD(constructor, "compactRange", CompactRange);

  // Static methods
  NODE_SET_METHOD(target, "open", Open);
  NODE_SET_METHOD(target, "destroy", Destroy);
  NODE_SET_METHOD(target, "repair", Repair);

  // Set version
  std::stringstream version;
  version << leveldb::kMajorVersion << "." << leveldb::kMinorVersion;
  target->Set(String::New("bindingVersion"),
              String::New(version.str().c_str()),
              static_cast<PropertyAttribute>(ReadOnly|DontDelete));
}

Handle<Value> JHandle::New(const Arguments& args) {
  HandleScope scope;

  assert(args.Length() == 2);
  assert(args[0]->IsExternal());

  leveldb::DB* db = (leveldb::DB*)External::Unwrap(args[0]);
  JHandle* self = new JHandle(db);

  if (args[1]->IsExternal())
    self->comparator_ = Persistent<Value>::New(args[1]);

  self->Wrap(args.This());

  return args.This();
}

/**

    Open

 */

typedef struct open_params {
  std::string name_;

  leveldb::Options options_;
  leveldb::Status status_;
  leveldb::DB* db_;

  Persistent<Value> comparator_;
  Persistent<Function> callback_;

  virtual ~open_params() {
    comparator_.Dispose();
    callback_.Dispose();
  }
} open_params_t;

static void AsyncOpen(uv_work_t* req) {
  open_params_t* op = static_cast<open_params_t*>(req->data);
  op->status_ = leveldb::DB::Open(op->options_, op->name_, &op->db_);
}

static void AfterOpen(uv_work_t* req) {
  HandleScope scope;
  open_params_t* op = static_cast<open_params_t*>(req->data);
  assert(!op->callback_.IsEmpty());

  Handle<Value> error = Null();
  Handle<Value> result = Undefined();

  if (op->status_.ok()) {
    Handle<Value> args[] = { External::New(op->db_), Undefined() };
    if (!op->comparator_.IsEmpty()) args[1] = op->comparator_;
    result = JHandle::constructor->GetFunction()->NewInstance(2, args);
  } else {
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
  }

  Handle<Value> argv[] = { error, result };

  TryCatch tryCatch;
  op->callback_->Call(Context::GetCurrent()->Global(), 2, argv);
  if (tryCatch.HasCaught()) FatalException(tryCatch);

  delete op;
  delete req;
}

Handle<Value> JHandle::Open(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 3 ||
      !args[0]->IsString() ||
      !args[2]->IsFunction())
    return ThrowTypeError("Invalid arguments");

  open_params_t* op = new open_params_t;

  // Required filename
  op->name_ = *String::Utf8Value(args[0]);

  // Required callback
  op->callback_ = Persistent<Function>::New(Local<Function>::Cast(args[2]));

  // Optional options
  UnpackOptions(args[1], op->options_, &op->comparator_);

  AsyncQueue(op, AsyncOpen, AfterOpen);

  return Undefined();
}

/**

    Destroy

 */

typedef struct dbop_params {
  std::string name_;

  leveldb::Options options_;
  leveldb::Status status_;

  Persistent<Function> callback_;

  virtual ~dbop_params() {
    callback_.Dispose();
  }
} dbop_params_t;

static void AfterDbOp(uv_work_t* req) {
  HandleScope scope;
  dbop_params* op = static_cast<dbop_params*>(req->data);
  assert(!op->callback_.IsEmpty());

  Handle<Value> error = Null();

  if (!op->status_.ok()) {
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
  }

  Handle<Value> argv[] = { error };

  TryCatch tryCatch;
  op->callback_->Call(Context::GetCurrent()->Global(), 1, argv);
  if (tryCatch.HasCaught()) FatalException(tryCatch);

  delete op;
  delete req;
}

static void AsyncDestroy(uv_work_t* req) {
  open_params_t* op = static_cast<open_params_t*>(req->data);
  op->status_ = leveldb::DestroyDB(op->name_, op->options_);
}

Handle<Value> JHandle::Destroy(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 3 || !args[0]->IsString())
    return ThrowTypeError("Invalid arguments");

  dbop_params_t* op = new dbop_params_t;

  // Required filename
  op->name_ = *String::Utf8Value(args[0]);

  // Optional options
  UnpackOptions(args[1], op->options_);

  // Optional callback
  if (args[2]->IsFunction())
    op->callback_ = Persistent<Function>::New(Local<Function>::Cast(args[2]));

  AsyncQueue(op, AsyncDestroy, AfterDbOp);

  return Undefined();
}

/**

    Repair

 */

Handle<Value> JHandle::Repair(const Arguments& args) {
  HandleScope scope;

  if (args.Length() < 1 || !args[0]->IsString())
    return ThrowTypeError("Invalid arguments");

  OpenOp* op = OpenOp::New(Repair, OpenConv, args);
  op->name_ = *String::Utf8Value(args[0]);

  // Optional options
  if (args.Length() > 1) UnpackOptions(args[1], op->options_);

  return op->Run();
}

Handle<Value> JHandle::Read(const Arguments& args) {
  HandleScope scope;

  int argc = args.Length();
  if (argc < 1 || !Buffer::HasInstance(args[0]))
    return ThrowTypeError("Invalid arguments");

  ReadOp* op = ReadOp::New(Read, Read, args);
  op->key_ = ToSlice(args[0], op->keyHandle_);

  // Optional read options
  if (argc > 1) UnpackReadOptions(args[1], op->options_);

  return op->Run();
}

Handle<Value> JHandle::Write(const Arguments& args) {
  HandleScope scope;

  int argc = args.Length();
  if (argc < 1 || !JBatch::HasInstance(args[0]))
    return ThrowTypeError("Invalid arguments");

  WriteOp* op = WriteOp::New(Write, Write, args);
  op->batch_ = ObjectWrap::Unwrap<JBatch>(args[0]->ToObject());

  // Optional write options
  if (argc > 1) UnpackWriteOptions(args[1], op->options_);

  return op->Run();
}

Handle<Value> JHandle::RefIterator(leveldb::Iterator* it) {
  Local<Value> argv[] = { External::New(it) };
  Local<Object> instance = JIterator::constructor->GetFunction()->NewInstance(1, argv);

  // Keep a weak reference
  Persistent<Object> weak = Persistent<Object>::New(instance);
  weak.MakeWeak(this, &UnrefIterator);

  Ref();

  return instance;
}

void JHandle::UnrefIterator(Persistent<Value> object, void* parameter) {
  assert(object->IsObject());

  JHandle* self = static_cast<JHandle*>(parameter);
  assert(self);

  self->Unref();
  object.Dispose();
}

Handle<Value> JHandle::Iterator(const Arguments& args) {
  HandleScope scope;
  IteratorOp* op = IteratorOp::New(Iterator, Iterator, args);
  if (args.Length() > 0) UnpackReadOptions(args[0], op->options_);
  return op->Run();
}

Handle<Value> JHandle::RefSnapshot(const leveldb::Snapshot* snapshot) {
  Local<Value> instance = External::New((void*)snapshot);
  Persistent<Value> weak = Persistent<Value>::New(instance);
  weak.MakeWeak(this, &UnrefSnapshot);
  Ref();
  return instance;
}

void JHandle::UnrefSnapshot(Persistent<Value> object, void* parameter) {
  assert(object->IsExternal());

  JHandle* self = static_cast<JHandle*>(parameter);
  leveldb::Snapshot* snapshot =
    static_cast<leveldb::Snapshot*>(External::Unwrap(object));

  assert(self);
  assert(snapshot);

  self->db_->ReleaseSnapshot(snapshot);
  self->Unref();

  object.Dispose();
}

Handle<Value> JHandle::Snapshot(const Arguments& args) {
  HandleScope scope;
  return SnapshotOp::Go(Snapshot, Snapshot, args);
}

Handle<Value> JHandle::Property(const Arguments& args) {
  HandleScope scope;

  if (args.Length() < 1 || !args[0]->IsString())
    return ThrowTypeError("Invalid arguments");

  PropertyOp* op = PropertyOp::New(Property, Property, args);
  op->name_ = *String::Utf8Value(args[0]);

  return op->Run();
}

Handle<Value> JHandle::ApproximateSizes(const Arguments& args) {
  HandleScope scope;

  if (args.Length() < 1 || !args[0]->IsArray())
    return ThrowTypeError("Invalid arguments");

  Local<Array> array(Array::Cast(*args[0]));

  int len = array->Length();
  if (len % 2 != 0)
    return ThrowTypeError("Invalid arguments");

  ApproximateSizesOp* op =
    ApproximateSizesOp::New(ApproximateSizes, ApproximateSizes, args);

  for (int i = 0; i < len; i += 2) {
    if (array->Has(i) && array->Has(i + 1)) {
      Local<Value> lStart = array->Get(i);
      Local<Value> lLimit = array->Get(i + 1);

      leveldb::Slice start = ToSlice(lStart, op->handles_);
      leveldb::Slice limit = ToSlice(lLimit, op->handles_);

      op->ranges_.push_back(leveldb::Range(start, limit));
    }
  }

  return op->Run();
}

Handle<Value> JHandle::CompactRange(const Arguments& args) {
  HandleScope scope;
  return ThrowError("Method not implemented");
}

//
// ASYNC FUNCTIONS
//

void JHandle::Repair(OpenOp* op) {
  op->status_ = leveldb::RepairDB(op->name_, op->options_);
}

void JHandle::OpenConv(OpenOp* op, Handle<Value>& error, Handle<Value>& result) {
  if (!op->status_.ok())
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
}

void JHandle::Read(ReadOp* op) {
  op->result_ = new std::string;
  op->status_ = op->self_->db_->Get(op->options_, op->key_, op->result_);
}

void JHandle::Read(ReadOp* op, Handle<Value>& error, Handle<Value>& result) {
  if (op->status_.ok()) {
    result = ToBuffer(op->result_);
  } else if (!op->status_.IsNotFound()) {
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
  }
}

void JHandle::Write(WriteOp* op) {
  op->batch_->ReadLock();
  op->status_ = op->self_->db_->Write(op->options_, &op->batch_->wb_);
  op->batch_->ReadUnlock();
}

void JHandle::Write(WriteOp* op, Handle<Value>& error, Handle<Value>& result) {
  if (!op->status_.ok())
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
}

void JHandle::Iterator(IteratorOp* op) {
  op->it_ = op->self_->db_->NewIterator(op->options_);
}

void JHandle::Iterator(IteratorOp* op, Handle<Value>& error, Handle<Value>& result) {
  if (op->status_.ok()) {
    result = op->self_->RefIterator(op->it_);
  } else {
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
  }
}

void JHandle::Snapshot(SnapshotOp* op) {
  op->snap_ = const_cast<leveldb::Snapshot*>(op->self_->db_->GetSnapshot());
}

void JHandle::Snapshot(SnapshotOp* op, Handle<Value>& error, Handle<Value>& result) {
  if (op->status_.ok()) {
    result = op->self_->RefSnapshot(op->snap_);
  } else {
    error = Exception::Error(String::New(op->status_.ToString().c_str()));
  }
}

void JHandle::Property(PropertyOp* op) {
  leveldb::Slice name(op->name_);
  op->hasProperty_ = op->self_->db_->GetProperty(name, &op->value_);
}

void JHandle::Property(PropertyOp* op, Handle<Value>& error, Handle<Value>& result) {
  if (op->hasProperty_) result = String::New(op->value_.c_str());
}

void JHandle::ApproximateSizes(ApproximateSizesOp* op) {
  int len = op->ranges_.size();
  op->sizes_ = new uint64_t[len];
  op->self_->db_->GetApproximateSizes(&op->ranges_[0], len, op->sizes_);
}

void JHandle::ApproximateSizes(ApproximateSizesOp* op,
                               Handle<Value>& error, Handle<Value>& result)
{
  int len = op->ranges_.size();

  Handle<Array> array = Array::New(len);

  for (int i = 0; i < len; ++i) {
    uint64_t size = op->sizes_[i];
    if (size < INT_MAX) {
      array->Set(i, Integer::New(static_cast<uint32_t>(size)));
    } else {
      array->Set(i, Number::New(static_cast<double>(size)));
    }
  }

  result = array;
}

} // namespace node_leveldb
<|endoftext|>