<commit_before>/**@addtogroup Probe Test whether a given port on a host is connectable.
 * @{@file
 *
 * This application attempts to connect to a server and port, and just returns
 * the status as a result to the invoker.
 *
 * @author Nigel Bree <nigel.bree@gmail.com>
 *
 * Copyright (C) 2011 Nigel Bree; All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <winsock2.h>
#include <ws2tcpip.h>

/**
 * Cliche for returning array lengths.
 */

#define ARRAY_LENGTH(a) (sizeof (a) / sizeof ((a) [0]))

/**
 * Simple command-line argument extraction, about as unsophisticated as it can
 * possibly get.
 */

wchar_t * split (wchar_t * args) {
        if (args == 0)
                return args;

        /*
         * The argument is quoted (which is typical of the first argument, the
         * program name, because of the need to avoid problems with spaces in
         * the path), in which case we skip to the ending quote first.
         */

        if (* args == '"') {
                for (;;) {
                        ++ args;
                        wchar_t         ch = * args;
                        if (ch == '"')
                                break;

                        if (ch == 0)
                                return 0;
                }
        }

        /*
         * Split at the next space.
         */

        for (;;) {
                wchar_t         ch = * args;
                if (ch == ' ')
                        break;

                if (ch == 0)
                        return 0;
                ++ args;
        }

        * args = 0;
        ++ args;

        /*
         * If there are additional spaces, consume them.
         */

        while (* args == ' ')
                ++ args;

        return args;
}

/**
 * If we're asked to probe for an NTTP port, then sometimes we have to deal
 * with local proxies.
 *
 * In this case, we actually try and read from the socket to at least get the
 * server's initial hello. For the annoying Avast! proxy, that at least does
 * not get sent until the real target responds to the proxy, and if the proxy
 * connection doesn't work (after 5-6 seconds, since it tries the TLS version
 * of the port even if we connected plain-text) then it spits a 400 out.
 */

int checkNntp (SOCKET s) {
        char            buf [128];
        int             result;
        result = recv (s, buf, sizeof (buf), 0);
        if (result < 5)
                return 1;

        /*
         * Various tedious socket-isms can apply, such as the bytes for the
         * initial response code trickling in over time. Let's not worry
         * about that, just deal with the basics.
         */

        void          * end = memchr (buf, ' ', result);
        if (end == 0)
                return 1;

        return memcmp (buf, "400", 3) == 0 ? 1 : 0;
}

/**
 * If we're asked to probe for an HTTP port, then we need to avoid problems
 * with local proxies.
 *
 * Unlike NNTP, the HTTP protocol is client-driven; as it turns out the way the
 * crappy Avast! proxy works is that it'll unilaterally close the connection if
 * it can't reach the real intended target, but in order to have this work for
 * real targets it pays to request a resource. The safest thing to ask for seems
 * to be favicon.ico - it's something lots of browsers request anyway and it's
 * almost always a small image, so we shouldn't clog up logs with requests for
 * 404 resources or get elaborate 404 response pages back.
 *
 * It turns out that the Avast! proxy has some other exciting misbehaviours; it
 * will sometimes (but not always) when a connection fails return an "HTTP/1.1
 * 200 OK" status with some fixed bogus fields, one of which is a "Refresh: 1;"
 * to re-fetch the target URL.
 */

int checkHttp (SOCKET s, HANDLE show) {
static  char            head [] = "HEAD /favicon.ico HTTP/1.0\n\n";
        int             result;
        int             length = strlen (head);
        result = send (s, head, length, 0);
        if (result < length)
                return 1;

        char            buf [1024];
        result = recv (s, buf, sizeof (buf) - 1, 0);

#if     1
        /*
         * Show the HTTP response, for debugging. I'll keep this in as long as
         * it doesn't cost me any compile-time space.
         */

        if (result > 0 && show > 0) {
                HANDLE          err = GetStdHandle (STD_ERROR_HANDLE);
                unsigned long   written = 0;
                WriteFile (err, buf, result, & written, 0);
        }
#endif

        /*
         * Normally we wouldn't care what the actual response text was, but to
         * deal with the fake response sometimes returned from Avast! I have to
         * recognize and suppress it.
         */

        if (result > 0) {
                buf [result] = 0;
                if (strstr (buf, "\nRefresh: 1;") != 0)
                        return 1;
        }

        return result < 5 ? 1 : 0;
}

/**
 * Probe for the indicated port at the given host.
 */

int probe (wchar_t * host, wchar_t * port, HANDLE show) {
        /*
         * Detect the presence of the Avast! virus scanner; it includes a set
         * of proxy-type firewalls that are somewhat tedious to deal with, and
         * in the case of NNTP mean that NNTP connections go through their
         * proxy; so, our connect will succeed (being locally looped back) and
         * send us nothing while the proxy module slowly decides whether it can
         * or can't connect to the real target over TLS or plain-text NNTP.
         *
         * So, if Avast! is present we can choose to either try and read from
         * the socket once it connects (so we can get the response code, which
         * will generally be 400 once the Avast proxy fails), or we can forget
         * the whole probing process because that introduces too much delay.
         */

        HMODULE         avast = GetModuleHandle (L"snxhk.dll");

        SOCKET          s;
        s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (s == SOCKET_ERROR)
                return 2;

        sockaddr_in     any;
        any.sin_family = AF_INET;
        any.sin_port = 0;
        any.sin_addr.S_un.S_addr = INADDR_ANY;
        if (bind (s, (sockaddr *) & any, sizeof (any)) != 0)
                return 2;

        /*
         * Look up the hostname and convert the port number into numeric form,
         * all handily in one function.
         */

        ADDRINFOW     * address;
        if (GetAddrInfoW (host, port, 0, & address) != 0)
                return 2;

        /*
         * Ensure that we only connect via IPv4, having made an IPv4 socket
         * already (yes, I could do things in a different order, but for my
         * purposes here with Steam I care about IPv4 only for now since they
         * are IPv4-only).
         */

        while (address->ai_addr->sa_family != AF_INET)
                if ((address = address->ai_next) == 0)
                        return 2;

        /*
         * Just test whether the port is open or not.
         */

        int             result;
        result = connect (s, address->ai_addr, address->ai_addrlen) ? 1 : 0;

        /*
         * Decide whether to actually wait for data, if we're dealing with the
         * Avast! proxy being present on a system.
         */

        sockaddr_in   * addr = (sockaddr_in *) address->ai_addr;
        switch (htons (addr->sin_port)) {
        case 119:
                if (avast && result == 0)
                        result = checkNntp (s);
                break;

        case 80:
                if (avast && result == 0)
                        result = checkHttp (s, show);
                break;

        default:
                break;
        }

        return result;
}

#include <iphlpapi.h>
#include <icmpapi.h>
#include "../steamfilter/glob.h"

/*
 * As an alternative to probing for a host, do a traceroute and permit glob
 * matches against the hostnames.
 *
 * In principle one could just script a traceroute, but that's a bit slow and
 * rather than writing a regex against the output it seems better to have a
 * more direct match available.
 */

int trace (wchar_t * host, wchar_t * pattern, HANDLE err) {
        HANDLE          icmp = IcmpCreateFile ();
        if (icmp == INVALID_HANDLE_VALUE)
                return 2;

        /*
         * Resolve an IPv4 hostname.
         */

        ADDRINFOW     * address;
        if (GetAddrInfoW (host, 0, 0, & address) != 0)
                return 2;

        /*
         * Ensure that we only connect via IPv4, having made an IPv4 socket
         * already (yes, I could do things in a different order, but for my
         * purposes here with Steam I care about IPv4 only for now since they
         * are IPv4-only).
         */

        while (address->ai_addr->sa_family != AF_INET)
                if ((address = address->ai_next) == 0)
                        return 2;

        sockaddr_in   * addr = (sockaddr_in *) address->ai_addr;
        IPAddr          dest = addr->sin_addr.s_addr;

        /*
         * The timeouts in this loop are tighter than they are in general kinds
         * of traceroute applications since we are generally probing for things
         * near to the origin system and with latencies in the <50ms bracket.
         */

        unsigned short  ttl = 1;
        for (; ttl < 5 ; ++ ttl) {
                unsigned char   buf [128];

                /*
                 * Part the first; send an echo request.
                 */

                IP_OPTION_INFORMATION info = { ttl };

                DWORD           echo;
                echo = IcmpSendEcho (icmp, dest, 0, 0, & info, buf, sizeof (buf), 50);
                if (echo < 1)
                        continue;

                /*
                 * We expect to see IP_TTL_EXPIRED_TRANSIT since we set the TTL
                 * to find the intermediate systems.
                 */

                ICMP_ECHO_REPLY * reply = (ICMP_ECHO_REPLY *) buf;
                if (reply->Status != IP_TTL_EXPIRED_TRANSIT && reply->Status != 0)
                        return 1;

                /*
                 * Part the second; protocol-independent reverse name lookup.
                 */

                sockaddr_in     find = { AF_INET };
                find.sin_addr.s_addr = reply->Address;
                find.sin_port = 0;

                char            name [128];
                char            port [20];
                unsigned long   error;
                error = getnameinfo ((SOCKADDR *) & find, sizeof (find),
                                     name, ARRAY_LENGTH (name),
                                     0, 0, NI_NAMEREQD);

                if (error != 0)
                        continue;

                /*
                 * We have a name, now we can glob-match it. If we see the
                 * desired pattern, we win. If we don't, we bail; the first
                 * name we resolve wins.
                 */

                return globMatch (name, pattern) ? 0 : 1;
        }

        return 1;
}

/**
 * This is intended as a "naked" WinMain without the Visual C++ run-time
 * at all (not just avoiding the broken locale machinery).
 */

int CALLBACK myWinMain (void) {
        HANDLE          err = GetStdHandle (STD_ERROR_HANDLE);
        unsigned long   written = 0;

        /*
         * Since we're not using the regular C machinery, get and split the
         * command line by hand. The CommandLineToArgvW () routine would do the
         * normal conversion to C style for us, but that depends on SHELL32.DLL
         * and we shouldn't need it.
         */

        wchar_t       * base = GetCommandLineW ();
        wchar_t       * name = split (base);
        wchar_t       * port = split (name);
        wchar_t       * extra = split (port);
        if (port == 0)
                return 2;
        WSADATA         wsaData;
        if (WSAStartup (MAKEWORD (2, 2), & wsaData) != 0)
                return 2;

        int             result;
        if (wcscmp (port, L"icmp") == 0) {
                result = trace (name, extra, err);
        } else {
                result = probe (name, port, err);
        }

        if (extra == 0)
                ExitProcess (result);

static  const char      text [] = "Probe result: ";
        WriteFile (err, text, strlen (text), & written, 0);

        char            buf [2] = { '0' + result };
        WriteFile (err, buf, 1, & written, 0);

        ExitProcess (result);
}
<commit_msg>Add some more polish to the probe utility to prepare for a v0.5.4.0 release<commit_after>/**@addtogroup Probe Test whether a given port on a host is connectable.
 * @{@file
 *
 * This application attempts to connect to a server and port, and just returns
 * the status as a result to the invoker.
 *
 * @author Nigel Bree <nigel.bree@gmail.com>
 *
 * Copyright (C) 2011 Nigel Bree; All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <winsock2.h>
#include <ws2tcpip.h>

/**
 * Cliche for returning array lengths.
 */

#define ARRAY_LENGTH(a) (sizeof (a) / sizeof ((a) [0]))

/**
 * Simple command-line argument extraction, about as unsophisticated as it can
 * possibly get.
 */

wchar_t * split (wchar_t * args) {
        if (args == 0)
                return args;

        /*
         * The argument is quoted (which is typical of the first argument, the
         * program name, because of the need to avoid problems with spaces in
         * the path), in which case we skip to the ending quote first.
         */

        wchar_t       * quoted = 0;
        if (* args == '"') {
                quoted = args;
                for (;;) {
                        ++ args;
                        wchar_t         ch = * args;
                        if (ch == '"')
                                break;

                        if (ch == 0)
                                return 0;
                }
        }

        /*
         * Split at the next space.
         */

        for (;;) {
                wchar_t         ch = * args;
                if (ch == ' ')
                        break;

                if (ch == 0)
                        return 0;
                ++ args;
        }

        * args = 0;
        ++ args;

        /*
         * If the arguments start with quotes, strip the quotes (this isn't a
         * completely generic thing to do, but it fits our purposes).
         */

        if (quoted) {
                wchar_t       * from = quoted;
                wchar_t         ch;
                while ((ch = * ++ quoted) != '"')
                        * from ++ = ch;

                while (ch != 0) {
                        ch = * ++ quoted;
                        * from ++ = ch;
                }

                * from = ch;
        }

        /*
         * If there are additional spaces, consume them.
         */

        while (* args == ' ')
                ++ args;

        return args;
}

/**
 * If we're asked to probe for an NTTP port, then sometimes we have to deal
 * with local proxies.
 *
 * In this case, we actually try and read from the socket to at least get the
 * server's initial hello. For the annoying Avast! proxy, that at least does
 * not get sent until the real target responds to the proxy, and if the proxy
 * connection doesn't work (after 5-6 seconds, since it tries the TLS version
 * of the port even if we connected plain-text) then it spits a 400 out.
 */

int checkNntp (SOCKET s) {
        char            buf [128];
        int             result;
        result = recv (s, buf, sizeof (buf), 0);
        if (result < 5)
                return 1;

        /*
         * Various tedious socket-isms can apply, such as the bytes for the
         * initial response code trickling in over time. Let's not worry
         * about that, just deal with the basics.
         */

        void          * end = memchr (buf, ' ', result);
        if (end == 0)
                return 1;

        return memcmp (buf, "400", 3) == 0 ? 1 : 0;
}

/**
 * If we're asked to probe for an HTTP port, then we need to avoid problems
 * with local proxies.
 *
 * Unlike NNTP, the HTTP protocol is client-driven; as it turns out the way the
 * crappy Avast! proxy works is that it'll unilaterally close the connection if
 * it can't reach the real intended target, but in order to have this work for
 * real targets it pays to request a resource. The safest thing to ask for seems
 * to be favicon.ico - it's something lots of browsers request anyway and it's
 * almost always a small image, so we shouldn't clog up logs with requests for
 * 404 resources or get elaborate 404 response pages back.
 *
 * It turns out that the Avast! proxy has some other exciting misbehaviours; it
 * will sometimes (but not always) when a connection fails return an "HTTP/1.1
 * 200 OK" status with some fixed bogus fields, one of which is a "Refresh: 1;"
 * to re-fetch the target URL.
 */

int checkHttp (SOCKET s, HANDLE show) {
static  char            head [] = "HEAD /favicon.ico HTTP/1.0\n\n";
        int             result;
        int             length = strlen (head);
        result = send (s, head, length, 0);
        if (result < length)
                return 1;

        char            buf [1024];
        result = recv (s, buf, sizeof (buf) - 1, 0);

        /*
         * Show the HTTP response, for debugging. I'll keep this in as long as
         * it doesn't cost me any compile-time space. I started out aiming to
         * keep this around 4kb, and now that the traceroute code is in the
         * aim is to keep it below 8kb.
         */

        if (result > 0 && show > 0) {
                unsigned long   written = 0;
                WriteFile (show, buf, result, & written, 0);
        }

        /*
         * Normally we wouldn't care what the actual response text was, but to
         * deal with the fake response sometimes returned from Avast! I have to
         * recognize and suppress it.
         */

        if (result > 0) {
                buf [result] = 0;
                if (strstr (buf, "\nRefresh: 1;") != 0)
                        return 1;
        }

        return result < 5 ? 1 : 0;
}

/**
 * Probe for the indicated port at the given host.
 */

int probe (wchar_t * host, wchar_t * port, HANDLE show) {
        /*
         * Detect the presence of the Avast! virus scanner; it includes a set
         * of proxy-type firewalls that are somewhat tedious to deal with, and
         * in the case of NNTP mean that NNTP connections go through their
         * proxy; so, our connect will succeed (being locally looped back) and
         * send us nothing while the proxy module slowly decides whether it can
         * or can't connect to the real target over TLS or plain-text NNTP.
         *
         * So, if Avast! is present we can choose to either try and read from
         * the socket once it connects (so we can get the response code, which
         * will generally be 400 once the Avast proxy fails), or we can forget
         * the whole probing process because that introduces too much delay.
         */

        HMODULE         avast = GetModuleHandle (L"snxhk.dll");

        SOCKET          s;
        s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (s == SOCKET_ERROR)
                return 2;

        sockaddr_in     any;
        any.sin_family = AF_INET;
        any.sin_port = 0;
        any.sin_addr.S_un.S_addr = INADDR_ANY;
        if (bind (s, (sockaddr *) & any, sizeof (any)) != 0)
                return 2;

        /*
         * Look up the hostname and convert the port number into numeric form,
         * all handily in one function.
         */

        ADDRINFOW     * address;
        if (GetAddrInfoW (host, port, 0, & address) != 0)
                return 2;

        /*
         * Ensure that we only connect via IPv4, having made an IPv4 socket
         * already (yes, I could do things in a different order, but for my
         * purposes here with Steam I care about IPv4 only for now since they
         * are IPv4-only).
         */

        while (address->ai_addr->sa_family != AF_INET)
                if ((address = address->ai_next) == 0)
                        return 2;

        /*
         * Just test whether the port is open or not.
         */

        int             result;
        result = connect (s, address->ai_addr, address->ai_addrlen) ? 1 : 0;

        /*
         * Decide whether to actually wait for data, if we're dealing with the
         * Avast! proxy being present on a system.
         */

        sockaddr_in   * addr = (sockaddr_in *) address->ai_addr;
        switch (htons (addr->sin_port)) {
        case 119:
                if (avast && result == 0)
                        result = checkNntp (s);
                break;

        case 80:
                if (avast && result == 0)
                        result = checkHttp (s, show);
                break;

        default:
                break;
        }

        return result;
}

#include <iphlpapi.h>
#include <icmpapi.h>
#include "../steamfilter/glob.h"

/*
 * As an alternative to probing for a host, do a traceroute and permit glob
 * matches against the hostnames.
 *
 * In principle one could just script a traceroute, but that's a bit slow and
 * rather than writing a regex against the output it seems better to have a
 * more direct match available.
 */

int trace (wchar_t * host, wchar_t * pattern, HANDLE err) {
        HANDLE          icmp = IcmpCreateFile ();
        if (icmp == INVALID_HANDLE_VALUE)
                return 2;

        /*
         * Resolve an IPv4 hostname.
         */

        ADDRINFOW     * address;
        if (GetAddrInfoW (host, 0, 0, & address) != 0)
                return 2;

        /*
         * Ensure that we only connect via IPv4, having made an IPv4 socket
         * already (yes, I could do things in a different order, but for my
         * purposes here with Steam I care about IPv4 only for now since they
         * are IPv4-only).
         */

        while (address->ai_addr->sa_family != AF_INET)
                if ((address = address->ai_next) == 0)
                        return 2;

        sockaddr_in   * addr = (sockaddr_in *) address->ai_addr;
        IPAddr          dest = addr->sin_addr.s_addr;

        /*
         * The timeouts in this loop are tighter than they are in general kinds
         * of traceroute applications since we are generally probing for things
         * near to the origin system and with latencies in the <50ms bracket.
         *
         * We'll also only use a relatively short TTL for the echo requests as
         * we're matching the first host with a DNS name. Also, some ISPs block
         * ICMP echo on their Steam servers (e.g. TelstraClear, who also keep
         * port 80 firewalled) so there's no point searching too hard since the
         * route will stall after only 2 or so hops.
         */

        unsigned short  ttl = 1;
        for (; ttl < 8 ; ++ ttl) {
                unsigned char   buf [128];

                /*
                 * Part the first; send an echo request.
                 */

                IP_OPTION_INFORMATION info = { ttl };

                DWORD           echo;
                echo = IcmpSendEcho (icmp, dest, 0, 0, & info, buf,
                                     sizeof (buf), 50);
                if (echo < 1) {
                        /*
                         * Allow one retry, "just in case".
                         */

                        echo = IcmpSendEcho (icmp, dest, 0, 0, & info, buf,
                                             sizeof (buf), 50);
                        if (echo < 1)
                                continue;
                }

                /*
                 * We expect to see IP_TTL_EXPIRED_TRANSIT since we set the TTL
                 * to find the intermediate systems.
                 */

                ICMP_ECHO_REPLY * reply = (ICMP_ECHO_REPLY *) buf;
                if (reply->Status != IP_TTL_EXPIRED_TRANSIT && reply->Status != 0)
                        return 1;

                /*
                 * Part the second; protocol-independent reverse name lookup.
                 */

                sockaddr_in     find = { AF_INET };
                find.sin_addr.s_addr = reply->Address;
                find.sin_port = 0;

                char            name [128];
                char            port [20];
                unsigned long   error;
                error = getnameinfo ((SOCKADDR *) & find, sizeof (find),
                                     name, ARRAY_LENGTH (name),
                                     0, 0, NI_NAMEREQD);

                if (error != 0)
                        continue;

                /*
                 * If we're given a handle to write to, print the name we found.
                 */

                unsigned long   written = 0;
                WriteFile (err, name, strlen (name), & written, 0);
                WriteFile (err, "\r\n", 2, & written, 0);

                /*
                 * If the status is 0, then we've hit the target host and that
                 * means we should stop and return 1.
                 */

                if (reply->Status == 0 || reply->Address == dest)
                        break;

                /*
                 * If the pattern is empty, we're just printing results.
                 */

                if (pattern == 0 || * pattern == 0)
                        continue;

                /*
                 * We have a name, now we can glob-match it. If we see the
                 * desired pattern, we win. If we don't, we bail; the first
                 * name we resolve wins.
                 */

                return globMatch (name, pattern) ? 0 : 1;
        }

        return 1;
}

/**
 * This is intended as a "naked" WinMain without the Visual C++ run-time
 * at all (not just avoiding the broken locale machinery).
 */

int CALLBACK myWinMain (void) {
        HANDLE          err = GetStdHandle (STD_ERROR_HANDLE);
        unsigned long   written = 0;

        /*
         * Since we're not using the regular C machinery, get and split the
         * command line by hand. The CommandLineToArgvW () routine would do the
         * normal conversion to C style for us, but that depends on SHELL32.DLL
         * and we shouldn't need it.
         */

        wchar_t       * base = GetCommandLineW ();
        wchar_t       * name = split (base);
        wchar_t       * port = split (name);
        wchar_t       * extra = split (port);
        if (port == 0)
                return 2;

        WSADATA         wsaData;
        if (WSAStartup (MAKEWORD (2, 2), & wsaData) != 0)
                return 2;

        int             result;
        if (wcscmp (port, L"icmp") == 0) {
                wchar_t       * find = extra;
                extra = split (find);
                if (find == 0 || * find == 0) {
                        /*
                         * If there is no third argument, just print the names
                         * of the first few systems we find.
                         */

                        find = 0;
                } else if (extra == 0)
                        err = INVALID_HANDLE_VALUE;

                result = trace (name, find, err);
        } else {
                if (extra == 0)
                        err = INVALID_HANDLE_VALUE;

                result = probe (name, port, err);
        }

        if (extra == 0)
                ExitProcess (result);

static  const char      text [] = "Probe result: ";
        WriteFile (err, text, strlen (text), & written, 0);

        char            buf [2] = { '0' + result };
        WriteFile (err, buf, 1, & written, 0);

        ExitProcess (result);
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/content_blocked_bubble_gtk.h"

#include "app/l10n_util.h"
#include "base/i18n/rtl.h"
#include "chrome/browser/blocked_popup_container.h"
#include "chrome/browser/content_setting_bubble_model.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/options/content_settings_window_gtk.h"
#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "gfx/gtk_util.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"

// Padding between content and edge of info bubble.
static const int kContentBorder = 7;

ContentSettingBubbleGtk::ContentSettingBubbleGtk(
    GtkWindow* toplevel_window,
    const gfx::Rect& bounds,
    InfoBubbleGtkDelegate* delegate,
    ContentSettingBubbleModel* content_setting_bubble_model,
    Profile* profile,
    TabContents* tab_contents)
    : toplevel_window_(toplevel_window),
      bounds_(bounds),
      profile_(profile),
      tab_contents_(tab_contents),
      delegate_(delegate),
      content_setting_bubble_model_(content_setting_bubble_model),
      info_bubble_(NULL) {
  registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
                 Source<TabContents>(tab_contents));
  BuildBubble();
}

ContentSettingBubbleGtk::~ContentSettingBubbleGtk() {
}

void ContentSettingBubbleGtk::Close() {
  if (info_bubble_)
    info_bubble_->Close();
}

void ContentSettingBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble,
                                                bool closed_by_escape) {
  delegate_->InfoBubbleClosing(info_bubble, closed_by_escape);
  delete this;
}

void ContentSettingBubbleGtk::Observe(NotificationType type,
                                      const NotificationSource& source,
                                      const NotificationDetails& details) {
  DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED);
  DCHECK(source == Source<TabContents>(tab_contents_));
  tab_contents_ = NULL;
}

void ContentSettingBubbleGtk::BuildBubble() {
  GtkThemeProvider* theme_provider = GtkThemeProvider::GetFrom(profile_);

  GtkWidget* bubble_content = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
  gtk_container_set_border_width(GTK_CONTAINER(bubble_content), kContentBorder);

  const ContentSettingBubbleModel::BubbleContent& content =
      content_setting_bubble_model_->bubble_content();
  if (!content.title.empty()) {
    // Add the content label.
    GtkWidget* label = gtk_label_new(content.title.c_str());
    gtk_box_pack_start(GTK_BOX(bubble_content), label, FALSE, FALSE, 0);
  }

  if (content_setting_bubble_model_->content_type() ==
      CONTENT_SETTINGS_TYPE_POPUPS) {
    const std::vector<ContentSettingBubbleModel::PopupItem>& popup_items =
        content.popup_items;
    GtkWidget* table = gtk_table_new(popup_items.size(), 2, FALSE);
    int row = 0;
    for (std::vector<ContentSettingBubbleModel::PopupItem>::const_iterator
         i(popup_items.begin()); i != popup_items.end(); ++i, ++row) {
      GtkWidget* image = gtk_image_new();
      if (!i->bitmap.empty()) {
        GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(&i->bitmap);
        gtk_image_set_from_pixbuf(GTK_IMAGE(image), icon_pixbuf);
        g_object_unref(icon_pixbuf);

        // We stuff the image in an event box so we can trap mouse clicks on the
        // image (and launch the popup).
        GtkWidget* event_box = gtk_event_box_new();
        gtk_container_add(GTK_CONTAINER(event_box), image);

        popup_icons_[event_box] = i -popup_items.begin();
        g_signal_connect(event_box, "button_press_event",
                         G_CALLBACK(OnPopupIconButtonPress), this);
        gtk_table_attach(GTK_TABLE(table), event_box, 0, 1, row, row + 1,
                         GTK_FILL, GTK_FILL, gtk_util::kControlSpacing / 2,
                         gtk_util::kControlSpacing / 2);
      }

      GtkWidget* button = gtk_chrome_link_button_new(i->title.c_str());
      popup_links_[button] = i -popup_items.begin();
      g_signal_connect(button, "clicked", G_CALLBACK(OnPopupLinkClicked),
                       this);
      gtk_table_attach(GTK_TABLE(table), button, 1, 2, row, row + 1,
                       GTK_FILL, GTK_FILL, gtk_util::kControlSpacing / 2,
                       gtk_util::kControlSpacing / 2);
    }

    gtk_box_pack_start(GTK_BOX(bubble_content), table, FALSE, FALSE, 0);
  }

  if (content_setting_bubble_model_->content_type() !=
      CONTENT_SETTINGS_TYPE_COOKIES) {
    const ContentSettingBubbleModel::RadioGroups& radio_groups =
        content.radio_groups;
    for (ContentSettingBubbleModel::RadioGroups::const_iterator i =
         radio_groups.begin(); i != radio_groups.end(); ++i) {
      const ContentSettingBubbleModel::RadioItems& radio_items = i->radio_items;
      RadioGroupGtk radio_group_gtk;
      for (ContentSettingBubbleModel::RadioItems::const_iterator j =
           radio_items.begin(); j != radio_items.end(); ++j) {
        GtkWidget* radio =
            radio_group_gtk.empty() ?
                gtk_radio_button_new_with_label(NULL, j->c_str()) :
                gtk_radio_button_new_with_label_from_widget(
                    GTK_RADIO_BUTTON(radio_group_gtk[0]),
                    j->c_str());
        gtk_box_pack_start(GTK_BOX(bubble_content), radio, FALSE, FALSE, 0);
        if (j - radio_items.begin() == i->default_item) {
          // We must set the default value before we attach the signal handlers
          // or pain occurs.
          gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
        }
        radio_group_gtk.push_back(radio);
      }
      for (std::vector<GtkWidget*>::const_iterator j = radio_group_gtk.begin();
           j != radio_group_gtk.end(); ++j) {
        g_signal_connect(*j, "toggled", G_CALLBACK(OnRadioToggled), this);
      }
      radio_groups_gtk_.push_back(radio_group_gtk);
      gtk_box_pack_start(GTK_BOX(bubble_content), gtk_hseparator_new(), FALSE,
                         FALSE, 0);
    }
  }

  for (std::vector<ContentSettingBubbleModel::DomainList>::const_iterator i =
       content.domain_lists.begin();
       i != content.domain_lists.end(); ++i) {
    // Put each list into its own vbox to allow spacing between lists.
    GtkWidget* list_content = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);

    GtkWidget* label = gtk_label_new(i->title.c_str());
    gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
    GtkWidget* label_box = gtk_hbox_new(FALSE, 0);
    gtk_box_pack_start(GTK_BOX(label_box), label, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(list_content), label_box, FALSE, FALSE, 0);
    for (std::set<std::string>::const_iterator j = i->hosts.begin();
         j != i->hosts.end(); ++j) {
      gtk_box_pack_start(GTK_BOX(list_content),
                         gtk_util::IndentWidget(gtk_util::CreateBoldLabel(*j)),
                         FALSE, FALSE, 0);
    }
    gtk_box_pack_start(GTK_BOX(bubble_content), list_content, FALSE, FALSE,
                       gtk_util::kControlSpacing);
  }

  if (!content.clear_link.empty()) {
    GtkWidget* clear_link_box = gtk_hbox_new(FALSE, 0);
    GtkWidget* clear_link = gtk_chrome_link_button_new(
        content.clear_link.c_str());
    g_signal_connect(clear_link, "clicked", G_CALLBACK(OnClearLinkClicked),
                     this);
    gtk_box_pack_start(GTK_BOX(clear_link_box), clear_link, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(bubble_content), clear_link_box,
                       FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(bubble_content), gtk_hseparator_new(),
                       FALSE, FALSE, 0);
  }

  GtkWidget* bottom_box = gtk_hbox_new(FALSE, 0);

  GtkWidget* manage_link =
      gtk_chrome_link_button_new(content.manage_link.c_str());
  g_signal_connect(manage_link, "clicked", G_CALLBACK(OnManageLinkClicked),
                   this);
  gtk_box_pack_start(GTK_BOX(bottom_box), manage_link, FALSE, FALSE, 0);

  GtkWidget* button = gtk_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DONE).c_str());
  g_signal_connect(button, "clicked", G_CALLBACK(OnCloseButtonClicked), this);
  gtk_box_pack_end(GTK_BOX(bottom_box), button, FALSE, FALSE, 0);

  gtk_box_pack_start(GTK_BOX(bubble_content), bottom_box, FALSE, FALSE, 0);
  gtk_widget_grab_focus(bottom_box);
  gtk_widget_grab_focus(button);

  InfoBubbleGtk::ArrowLocationGtk arrow_location =
      !base::i18n::IsRTL() ?
      InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT :
      InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT;
  info_bubble_ = InfoBubbleGtk::Show(
      toplevel_window_,
      bounds_,
      bubble_content,
      arrow_location,
      true,  // match_system_theme
      true,  // grab_input
      theme_provider,
      this);
}

// static
void ContentSettingBubbleGtk::OnPopupIconButtonPress(
    GtkWidget* icon_event_box,
    GdkEventButton* event,
    ContentSettingBubbleGtk* bubble) {
  PopupMap::iterator i(bubble->popup_icons_.find(icon_event_box));
  DCHECK(i != bubble->popup_icons_.end());
  bubble->content_setting_bubble_model_->OnPopupClicked(i->second);
  // The views interface implicitly closes because of the launching of a new
  // window; we need to do that explicitly.
  bubble->Close();

}

// static
void ContentSettingBubbleGtk::OnPopupLinkClicked(
    GtkWidget* button,
    ContentSettingBubbleGtk* bubble) {
  PopupMap::iterator i(bubble->popup_links_.find(button));
  DCHECK(i != bubble->popup_links_.end());
  bubble->content_setting_bubble_model_->OnPopupClicked(i->second);
  // The views interface implicitly closes because of the launching of a new
  // window; we need to do that explicitly.
  bubble->Close();
}

// static
void ContentSettingBubbleGtk::OnRadioToggled(
    GtkWidget* widget,
    ContentSettingBubbleGtk* bubble) {
  for (std::vector<RadioGroupGtk>::const_iterator i =
       bubble->radio_groups_gtk_.begin();
       i != bubble->radio_groups_gtk_.end(); ++i) {
    for (RadioGroupGtk::const_iterator j = i->begin(); j != i->end(); j++) {
      if (widget == *j) {
        bubble->content_setting_bubble_model_->OnRadioClicked(
            i - bubble->radio_groups_gtk_.begin(),
            j - i->begin());
        return;
      }
    }
  }
  NOTREACHED() << "unknown radio toggled";
}

// static
void ContentSettingBubbleGtk::OnCloseButtonClicked(
    GtkButton *button,
    ContentSettingBubbleGtk* bubble) {
  bubble->Close();
}

// static
void ContentSettingBubbleGtk::OnManageLinkClicked(
    GtkButton* button,
    ContentSettingBubbleGtk* bubble) {
  bubble->content_setting_bubble_model_->OnManageLinkClicked();
  bubble->Close();
}

void ContentSettingBubbleGtk::OnClearLinkClicked(
    GtkButton* button,
    ContentSettingBubbleGtk* bubble) {
  bubble->content_setting_bubble_model_->OnClearLinkClicked();
  bubble->Close();
}
<commit_msg>GTK: Left justify label in content blocking bubble.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/content_blocked_bubble_gtk.h"

#include "app/l10n_util.h"
#include "base/i18n/rtl.h"
#include "chrome/browser/blocked_popup_container.h"
#include "chrome/browser/content_setting_bubble_model.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/options/content_settings_window_gtk.h"
#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "gfx/gtk_util.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"

// Padding between content and edge of info bubble.
static const int kContentBorder = 7;

ContentSettingBubbleGtk::ContentSettingBubbleGtk(
    GtkWindow* toplevel_window,
    const gfx::Rect& bounds,
    InfoBubbleGtkDelegate* delegate,
    ContentSettingBubbleModel* content_setting_bubble_model,
    Profile* profile,
    TabContents* tab_contents)
    : toplevel_window_(toplevel_window),
      bounds_(bounds),
      profile_(profile),
      tab_contents_(tab_contents),
      delegate_(delegate),
      content_setting_bubble_model_(content_setting_bubble_model),
      info_bubble_(NULL) {
  registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
                 Source<TabContents>(tab_contents));
  BuildBubble();
}

ContentSettingBubbleGtk::~ContentSettingBubbleGtk() {
}

void ContentSettingBubbleGtk::Close() {
  if (info_bubble_)
    info_bubble_->Close();
}

void ContentSettingBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble,
                                                bool closed_by_escape) {
  delegate_->InfoBubbleClosing(info_bubble, closed_by_escape);
  delete this;
}

void ContentSettingBubbleGtk::Observe(NotificationType type,
                                      const NotificationSource& source,
                                      const NotificationDetails& details) {
  DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED);
  DCHECK(source == Source<TabContents>(tab_contents_));
  tab_contents_ = NULL;
}

void ContentSettingBubbleGtk::BuildBubble() {
  GtkThemeProvider* theme_provider = GtkThemeProvider::GetFrom(profile_);

  GtkWidget* bubble_content = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
  gtk_container_set_border_width(GTK_CONTAINER(bubble_content), kContentBorder);

  const ContentSettingBubbleModel::BubbleContent& content =
      content_setting_bubble_model_->bubble_content();
  if (!content.title.empty()) {
    // Add the content label.
    GtkWidget* label = gtk_label_new(content.title.c_str());
    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
    gtk_box_pack_start(GTK_BOX(bubble_content), label, FALSE, FALSE, 0);
  }

  if (content_setting_bubble_model_->content_type() ==
      CONTENT_SETTINGS_TYPE_POPUPS) {
    const std::vector<ContentSettingBubbleModel::PopupItem>& popup_items =
        content.popup_items;
    GtkWidget* table = gtk_table_new(popup_items.size(), 2, FALSE);
    int row = 0;
    for (std::vector<ContentSettingBubbleModel::PopupItem>::const_iterator
         i(popup_items.begin()); i != popup_items.end(); ++i, ++row) {
      GtkWidget* image = gtk_image_new();
      if (!i->bitmap.empty()) {
        GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(&i->bitmap);
        gtk_image_set_from_pixbuf(GTK_IMAGE(image), icon_pixbuf);
        g_object_unref(icon_pixbuf);

        // We stuff the image in an event box so we can trap mouse clicks on the
        // image (and launch the popup).
        GtkWidget* event_box = gtk_event_box_new();
        gtk_container_add(GTK_CONTAINER(event_box), image);

        popup_icons_[event_box] = i -popup_items.begin();
        g_signal_connect(event_box, "button_press_event",
                         G_CALLBACK(OnPopupIconButtonPress), this);
        gtk_table_attach(GTK_TABLE(table), event_box, 0, 1, row, row + 1,
                         GTK_FILL, GTK_FILL, gtk_util::kControlSpacing / 2,
                         gtk_util::kControlSpacing / 2);
      }

      GtkWidget* button = gtk_chrome_link_button_new(i->title.c_str());
      popup_links_[button] = i -popup_items.begin();
      g_signal_connect(button, "clicked", G_CALLBACK(OnPopupLinkClicked),
                       this);
      gtk_table_attach(GTK_TABLE(table), button, 1, 2, row, row + 1,
                       GTK_FILL, GTK_FILL, gtk_util::kControlSpacing / 2,
                       gtk_util::kControlSpacing / 2);
    }

    gtk_box_pack_start(GTK_BOX(bubble_content), table, FALSE, FALSE, 0);
  }

  if (content_setting_bubble_model_->content_type() !=
      CONTENT_SETTINGS_TYPE_COOKIES) {
    const ContentSettingBubbleModel::RadioGroups& radio_groups =
        content.radio_groups;
    for (ContentSettingBubbleModel::RadioGroups::const_iterator i =
         radio_groups.begin(); i != radio_groups.end(); ++i) {
      const ContentSettingBubbleModel::RadioItems& radio_items = i->radio_items;
      RadioGroupGtk radio_group_gtk;
      for (ContentSettingBubbleModel::RadioItems::const_iterator j =
           radio_items.begin(); j != radio_items.end(); ++j) {
        GtkWidget* radio =
            radio_group_gtk.empty() ?
                gtk_radio_button_new_with_label(NULL, j->c_str()) :
                gtk_radio_button_new_with_label_from_widget(
                    GTK_RADIO_BUTTON(radio_group_gtk[0]),
                    j->c_str());
        gtk_box_pack_start(GTK_BOX(bubble_content), radio, FALSE, FALSE, 0);
        if (j - radio_items.begin() == i->default_item) {
          // We must set the default value before we attach the signal handlers
          // or pain occurs.
          gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
        }
        radio_group_gtk.push_back(radio);
      }
      for (std::vector<GtkWidget*>::const_iterator j = radio_group_gtk.begin();
           j != radio_group_gtk.end(); ++j) {
        g_signal_connect(*j, "toggled", G_CALLBACK(OnRadioToggled), this);
      }
      radio_groups_gtk_.push_back(radio_group_gtk);
      gtk_box_pack_start(GTK_BOX(bubble_content), gtk_hseparator_new(), FALSE,
                         FALSE, 0);
    }
  }

  for (std::vector<ContentSettingBubbleModel::DomainList>::const_iterator i =
       content.domain_lists.begin();
       i != content.domain_lists.end(); ++i) {
    // Put each list into its own vbox to allow spacing between lists.
    GtkWidget* list_content = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);

    GtkWidget* label = gtk_label_new(i->title.c_str());
    gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
    GtkWidget* label_box = gtk_hbox_new(FALSE, 0);
    gtk_box_pack_start(GTK_BOX(label_box), label, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(list_content), label_box, FALSE, FALSE, 0);
    for (std::set<std::string>::const_iterator j = i->hosts.begin();
         j != i->hosts.end(); ++j) {
      gtk_box_pack_start(GTK_BOX(list_content),
                         gtk_util::IndentWidget(gtk_util::CreateBoldLabel(*j)),
                         FALSE, FALSE, 0);
    }
    gtk_box_pack_start(GTK_BOX(bubble_content), list_content, FALSE, FALSE,
                       gtk_util::kControlSpacing);
  }

  if (!content.clear_link.empty()) {
    GtkWidget* clear_link_box = gtk_hbox_new(FALSE, 0);
    GtkWidget* clear_link = gtk_chrome_link_button_new(
        content.clear_link.c_str());
    g_signal_connect(clear_link, "clicked", G_CALLBACK(OnClearLinkClicked),
                     this);
    gtk_box_pack_start(GTK_BOX(clear_link_box), clear_link, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(bubble_content), clear_link_box,
                       FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(bubble_content), gtk_hseparator_new(),
                       FALSE, FALSE, 0);
  }

  GtkWidget* bottom_box = gtk_hbox_new(FALSE, 0);

  GtkWidget* manage_link =
      gtk_chrome_link_button_new(content.manage_link.c_str());
  g_signal_connect(manage_link, "clicked", G_CALLBACK(OnManageLinkClicked),
                   this);
  gtk_box_pack_start(GTK_BOX(bottom_box), manage_link, FALSE, FALSE, 0);

  GtkWidget* button = gtk_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_DONE).c_str());
  g_signal_connect(button, "clicked", G_CALLBACK(OnCloseButtonClicked), this);
  gtk_box_pack_end(GTK_BOX(bottom_box), button, FALSE, FALSE, 0);

  gtk_box_pack_start(GTK_BOX(bubble_content), bottom_box, FALSE, FALSE, 0);
  gtk_widget_grab_focus(bottom_box);
  gtk_widget_grab_focus(button);

  InfoBubbleGtk::ArrowLocationGtk arrow_location =
      !base::i18n::IsRTL() ?
      InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT :
      InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT;
  info_bubble_ = InfoBubbleGtk::Show(
      toplevel_window_,
      bounds_,
      bubble_content,
      arrow_location,
      true,  // match_system_theme
      true,  // grab_input
      theme_provider,
      this);
}

// static
void ContentSettingBubbleGtk::OnPopupIconButtonPress(
    GtkWidget* icon_event_box,
    GdkEventButton* event,
    ContentSettingBubbleGtk* bubble) {
  PopupMap::iterator i(bubble->popup_icons_.find(icon_event_box));
  DCHECK(i != bubble->popup_icons_.end());
  bubble->content_setting_bubble_model_->OnPopupClicked(i->second);
  // The views interface implicitly closes because of the launching of a new
  // window; we need to do that explicitly.
  bubble->Close();

}

// static
void ContentSettingBubbleGtk::OnPopupLinkClicked(
    GtkWidget* button,
    ContentSettingBubbleGtk* bubble) {
  PopupMap::iterator i(bubble->popup_links_.find(button));
  DCHECK(i != bubble->popup_links_.end());
  bubble->content_setting_bubble_model_->OnPopupClicked(i->second);
  // The views interface implicitly closes because of the launching of a new
  // window; we need to do that explicitly.
  bubble->Close();
}

// static
void ContentSettingBubbleGtk::OnRadioToggled(
    GtkWidget* widget,
    ContentSettingBubbleGtk* bubble) {
  for (std::vector<RadioGroupGtk>::const_iterator i =
       bubble->radio_groups_gtk_.begin();
       i != bubble->radio_groups_gtk_.end(); ++i) {
    for (RadioGroupGtk::const_iterator j = i->begin(); j != i->end(); j++) {
      if (widget == *j) {
        bubble->content_setting_bubble_model_->OnRadioClicked(
            i - bubble->radio_groups_gtk_.begin(),
            j - i->begin());
        return;
      }
    }
  }
  NOTREACHED() << "unknown radio toggled";
}

// static
void ContentSettingBubbleGtk::OnCloseButtonClicked(
    GtkButton *button,
    ContentSettingBubbleGtk* bubble) {
  bubble->Close();
}

// static
void ContentSettingBubbleGtk::OnManageLinkClicked(
    GtkButton* button,
    ContentSettingBubbleGtk* bubble) {
  bubble->content_setting_bubble_model_->OnManageLinkClicked();
  bubble->Close();
}

void ContentSettingBubbleGtk::OnClearLinkClicked(
    GtkButton* button,
    ContentSettingBubbleGtk* bubble) {
  bubble->content_setting_bubble_model_->OnClearLinkClicked();
  bubble->Close();
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/transactiondescdialog.h>
#include <qt/forms/ui_transactiondescdialog.h>

#include <qt/transactiontablemodel.h>

#include <QModelIndex>

TransactionDescDialog::TransactionDescDialog(const QModelIndex &idx, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::TransactionDescDialog)
{
    ui->setupUi(this);
    setWindowTitle(tr("Details for %1").arg(idx.data(TransactionTableModel::TxHashRole).toString()));
    QString desc = idx.data(TransactionTableModel::LongDescriptionRole).toString();
    ui->detailText->setHtml(desc);
}

TransactionDescDialog::~TransactionDescDialog()
{
    delete ui;
}
<commit_msg>Port transaction description dialog<commit_after>// Copyright (c) 2011-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/transactiondescdialog.h>
#include <qt/forms/ui_transactiondescdialog.h>

#include <qt/transactiontablemodel.h>
#include <qt/styleSheet.h>

#include <QModelIndex>

TransactionDescDialog::TransactionDescDialog(const QModelIndex &idx, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::TransactionDescDialog)
{
    ui->setupUi(this);

    // Set stylesheet
    SetObjectStyleSheet(this, StyleSheetNames::ScrollBarDark);

    setWindowTitle(tr("Details for %1").arg(idx.data(TransactionTableModel::TxHashRole).toString()));
    QString desc = idx.data(TransactionTableModel::LongDescriptionRole).toString();
    ui->detailText->setHtml(desc);
}

TransactionDescDialog::~TransactionDescDialog()
{
    delete ui;
}
<|endoftext|>


<commit_before>/*
 * moneyServerClient2.cpp
 *
 *  Created on: 20. 7. 2017
 *      Author: ondra
 */

#include "moneyServerClient2.h"

#include <couchit/minihttp/buffered.h>
#include <imtjson/object.h>

#include "../common/runtime_error.h"

#include "error.h"

#include "logfile.h"
#include "orderBudget.h"

namespace quark {

MoneyServerClient2::MoneyServerClient2(PMoneySvcSupport support,
		String addr, String signature, String asset, String currency, String firstTradeId, bool logTrafic)
	:support(support)
	,addr(addr)
	,signature(signature)
	,asset(asset)
	,currency(currency)
	,firstTradeId(firstTradeId)
	,client(new MyClient(addr,*this))
	,inited(false)
{
	client->enableLogTrafic(logTrafic);
}

MoneyServerClient2::~MoneyServerClient2() {
	client->close();
}

void MoneyServerClient2::adjustBudget(json::Value ,
		OrderBudget& ) {
	//emoty
}

template<typename Fn>
void MoneyServerClient2::callWithRetry(RefCntPtr<MyClient> client,PMoneySvcSupport supp,  String methodName, Value params, Fn callback) {

	(*client)(methodName, params) >>
			[=](RpcResult res) {
		if (res.isError()) {
			if (res.defined()) {
				handleError(client,methodName,res);
			}
			if (!client->isClosed()) {
				supp->dispatch([=]{callWithRetry(client,supp,methodName,params,callback);});
			} else {
				callback(res);
			}
		} else {
			callback(res);
		}
	};

}

bool MoneyServerClient2::allocBudget(json::Value user, OrderBudget total,
		Callback callback) {

	connectIfNeed();
	RefCntPtr<MyClient> c(client);
	Value params = Object
			("user_id",user)
			("currency",total.currency)
			("asset",total.asset)
			("marginLong",total.marginLong)
			("marginShort",total.marginShort)
			("posLong",total.posLong)
			("posShort",total.posShort);

	(*client)("CurrencyBalance.block_money", params)
			>> [c,callback](const RpcResult &res) {

		if (res.isError()) {
			if (res.defined())
				handleError(c,"CurrencyBalance.block_money", res);
			callback(allocTryAgain);
		} else {
			if (Value(res)["success"].getBool()) {
				callback(allocOk);
			} else {
				callback(allocReject);
			}
		}

	};
	return false;

}

void MoneyServerClient2::reportTrade(Value prevTrade, const TradeData& data) {

	 connectIfNeed();
	 reportTrade2(prevTrade, data);

}
void MoneyServerClient2::reportTrade2(Value prevTrade, const TradeData& data) {

	RefCntPtr<MyClient> c(client);
	(*c)("CurrencyBalance.trade", Object("trade_id",data.id)
										("prev_trade_id", prevTrade)
										("timestamp",data.timestamp)
										("asset",data.size)
										("currency",data.price)
										("buyer",Object("user_id",data.buyer.userId)
													   ("context",data.buyer.context))
										("seller",Object("user_id",data.seller.userId)
													   ("context",data.seller.context))
										("taker",data.dir == OrderDir::buy?"buyer":"seller"))

	>> [c](const RpcResult &res){
		if (res.isError()) {
			handleError(c, "CurrencyBalance.trade", res);
		}
	};
	lastReportedTrade = data.id;
}

MoneyServerClient2::MyClient::MyClient(String addr,
		MoneyServerClient2& owner):owner(owner),closed(false) {
}

void MoneyServerClient2::MyClient::onInit() {
	owner.onInit();
}

void MoneyServerClient2::MyClient::onNotify(const Notify& ntf) {
	owner.onNotify(ntf);
}

void MoneyServerClient2::onInit() {
	//empty
}

void MoneyServerClient2::onNotify(const Notify& ntf) {
	//empty
}

class MoneyServerClient2::ResyncStream: public ITradeStream {
public:
	MoneyServerClient2 &owner;
	ResyncStream(MoneyServerClient2 &owner):owner(owner) {}
	virtual void reportTrade(Value prevTrade, const TradeData &data) {
		owner.reportTrade2(prevTrade, data);
	}
};

void MoneyServerClient2::connectIfNeed() {
	if (!client->isConnected()) {
		if (client->connect(addr)) {

			RpcResult initres = (*client)("CurrencyBalance.init", Object
					("signature",signature)
					("asset",asset)
					("currency",currency));
			if (initres.isError()) {
				if (initres.defined()) {
					handleError(client,"CurrencyBalance.init", initres);
				}
			} else {
				Value r(initres);
				Value lastSyncId = r["last_trade_id"];
				Value version = r["version"];

				if (lastSyncId.getString() == "" && firstTradeId != "") {
					lastSyncId = firstTradeId;
				}

				logInfo({"Initialized RPC client, version, lastId", version, lastSyncId});

				ResyncStream resyncStream(*this);
				support->resync(resyncStream, lastSyncId, lastReportedTrade);
			}

		} else {
			//failed connect
			//nothing here - commands send to disconnected client are rejected through callback
		}
	}
}

void MoneyServerClient2::handleError(MyClient *c, StrViewA method, const RpcResult& res)
{
	logError({method, "Money server error, dropping connection", c->getAddr(), Value(res)});
	c->disconnect(false);
}

}
<commit_msg>error during sync -> unhandled exception<commit_after>/*
 * moneyServerClient2.cpp
 *
 *  Created on: 20. 7. 2017
 *      Author: ondra
 */

#include "moneyServerClient2.h"

#include <couchit/minihttp/buffered.h>
#include <imtjson/object.h>

#include "../common/runtime_error.h"

#include "error.h"

#include "logfile.h"
#include "orderBudget.h"

namespace quark {

MoneyServerClient2::MoneyServerClient2(PMoneySvcSupport support,
		String addr, String signature, String asset, String currency, String firstTradeId, bool logTrafic)
	:support(support)
	,addr(addr)
	,signature(signature)
	,asset(asset)
	,currency(currency)
	,firstTradeId(firstTradeId)
	,client(new MyClient(addr,*this))
	,inited(false)
{
	client->enableLogTrafic(logTrafic);
}

MoneyServerClient2::~MoneyServerClient2() {
	client->close();
}

void MoneyServerClient2::adjustBudget(json::Value ,
		OrderBudget& ) {
	//emoty
}

template<typename Fn>
void MoneyServerClient2::callWithRetry(RefCntPtr<MyClient> client,PMoneySvcSupport supp,  String methodName, Value params, Fn callback) {

	(*client)(methodName, params) >>
			[=](RpcResult res) {
		if (res.isError()) {
			if (res.defined()) {
				handleError(client,methodName,res);
			}
			if (!client->isClosed()) {
				supp->dispatch([=]{callWithRetry(client,supp,methodName,params,callback);});
			} else {
				callback(res);
			}
		} else {
			callback(res);
		}
	};

}

bool MoneyServerClient2::allocBudget(json::Value user, OrderBudget total,
		Callback callback) {

	connectIfNeed();
	RefCntPtr<MyClient> c(client);
	Value params = Object
			("user_id",user)
			("currency",total.currency)
			("asset",total.asset)
			("marginLong",total.marginLong)
			("marginShort",total.marginShort)
			("posLong",total.posLong)
			("posShort",total.posShort);

	(*client)("CurrencyBalance.block_money", params)
			>> [c,callback](const RpcResult &res) {

		if (res.isError()) {
			if (res.defined())
				handleError(c,"CurrencyBalance.block_money", res);
			callback(allocTryAgain);
		} else {
			if (Value(res)["success"].getBool()) {
				callback(allocOk);
			} else {
				callback(allocReject);
			}
		}

	};
	return false;

}

void MoneyServerClient2::reportTrade(Value prevTrade, const TradeData& data) {

	 connectIfNeed();
	 reportTrade2(prevTrade, data);

}
void MoneyServerClient2::reportTrade2(Value prevTrade, const TradeData& data) {

	RefCntPtr<MyClient> c(client);
	(*c)("CurrencyBalance.trade", Object("trade_id",data.id)
										("prev_trade_id", prevTrade)
										("timestamp",data.timestamp)
										("asset",data.size)
										("currency",data.price)
										("buyer",Object("user_id",data.buyer.userId)
													   ("context",data.buyer.context))
										("seller",Object("user_id",data.seller.userId)
													   ("context",data.seller.context))
										("taker",data.dir == OrderDir::buy?"buyer":"seller"))

	>> [c](const RpcResult &res){
		if (res.isError()) {
			handleError(c, "CurrencyBalance.trade", res);
		}
	};
	lastReportedTrade = data.id;
}

MoneyServerClient2::MyClient::MyClient(String addr,
		MoneyServerClient2& owner):owner(owner),closed(false) {
}

void MoneyServerClient2::MyClient::onInit() {
	owner.onInit();
}

void MoneyServerClient2::MyClient::onNotify(const Notify& ntf) {
	owner.onNotify(ntf);
}

void MoneyServerClient2::onInit() {
	//empty
}

void MoneyServerClient2::onNotify(const Notify& ntf) {
	//empty
}

class MoneyServerClient2::ResyncStream: public ITradeStream {
public:
	MoneyServerClient2 &owner;
	ResyncStream(MoneyServerClient2 &owner):owner(owner) {}
	virtual void reportTrade(Value prevTrade, const TradeData &data) {
		owner.reportTrade2(prevTrade, data);
	}
};

void MoneyServerClient2::connectIfNeed() {
	if (!client->isConnected()) {
		if (client->connect(addr)) {

			RpcResult initres = (*client)("CurrencyBalance.init", Object
					("signature",signature)
					("asset",asset)
					("currency",currency));
			if (initres.isError()) {
				if (initres.defined()) {
					handleError(client,"CurrencyBalance.init", initres);
				}
			} else {
				Value r(initres);
				Value lastSyncId = r["last_trade_id"];
				Value version = r["version"];

				if (lastSyncId.getString() == "" && firstTradeId != "") {
					lastSyncId = firstTradeId;
				}

				logInfo({"Initialized RPC client, version, lastId", version, lastSyncId});

				try {
					ResyncStream resyncStream(*this);
					support->resync(resyncStream, lastSyncId, lastReportedTrade);
				}  catch (...) {
					unhandledException();
				}
			}

		} else {
			//failed connect
			//nothing here - commands send to disconnected client are rejected through callback
		}
	}
}

void MoneyServerClient2::handleError(MyClient *c, StrViewA method, const RpcResult& res)
{
	logError({method, "Money server error, dropping connection", c->getAddr(), Value(res)});
	c->disconnect(false);
}

}
<|endoftext|>


<commit_before>#include "audio/playback.h"

namespace loftili {

namespace audio {

void Playback::Start() {
  if(m_state == PLAYBACK_STATE_PLAYING) return;
  spdlog::get(LOFTILI_SPDLOG_ID)->info("playback starting, opening playback thread");
  m_state = PLAYBACK_STATE_PLAYING;
  m_stateclient.Update("playback", 1);
  m_thread = std::unique_ptr<std::thread>(new std::thread(std::bind(&Playback::Run, this)));
}

void Playback::Skip() {
  Stop();
  m_queue.Pop();
  Start();
}

void Playback::Stop() {
  spdlog::get(LOFTILI_SPDLOG_ID)->info("stopping player and playback run thread");
  m_state = PLAYBACK_STATE_STOPPED;
  m_player.Stop();
  m_thread->join();
}

void Playback::Run() {
  m_state = PLAYBACK_STATE_PLAYING;

  while(m_queue >> m_player && m_state == PLAYBACK_STATE_PLAYING) {
    spdlog::get(LOFTILI_SPDLOG_ID)->info("player finished, getting next track from queue");
  }

  spdlog::get(LOFTILI_SPDLOG_ID)->info("playback run thread finishing");
  m_state = PLAYBACK_STATE_STOPPED;
  m_stateclient.Update("playback", 0);
}

}

}
<commit_msg>[LFTCE-36] checking that device state playing before attempting to stop in playback skip<commit_after>#include "audio/playback.h"

namespace loftili {

namespace audio {

void Playback::Start() {
  if(m_state == PLAYBACK_STATE_PLAYING) return;
  spdlog::get(LOFTILI_SPDLOG_ID)->info("playback starting, opening playback thread");
  m_state = PLAYBACK_STATE_PLAYING;
  m_stateclient.Update("playback", 1);
  m_thread = std::unique_ptr<std::thread>(new std::thread(std::bind(&Playback::Run, this)));
}

void Playback::Skip() {
  if(m_state == PLAYBACK_STATE_PLAYING) Stop();
  m_queue.Pop();
  Start();
}

void Playback::Stop() {
  spdlog::get(LOFTILI_SPDLOG_ID)->info("stopping player and playback run thread");
  m_state = PLAYBACK_STATE_STOPPED;
  m_player.Stop();
  m_thread->join();
}

void Playback::Run() {
  m_state = PLAYBACK_STATE_PLAYING;

  while(m_queue >> m_player && m_state == PLAYBACK_STATE_PLAYING) {
    spdlog::get(LOFTILI_SPDLOG_ID)->info("player finished, getting next track from queue");
  }

  spdlog::get(LOFTILI_SPDLOG_ID)->info("playback run thread finishing");
  m_state = PLAYBACK_STATE_STOPPED;
  m_stateclient.Update("playback", 0);
}

}

}
<|endoftext|>


<commit_before>/*******************************************************************************
 * c7a/core/stage_builder.hpp
 *
 * Part of Project c7a.
 *
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_CORE_STAGE_BUILDER_HEADER
#define C7A_CORE_STAGE_BUILDER_HEADER

#include <c7a/api/dia_base.hpp>
#include <c7a/common/logger.hpp>

#include <algorithm>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>

namespace c7a {
namespace core {

using c7a::api::DIABase;

class Stage
{
public:
    explicit Stage(DIABase* node) : node_(node) {
        LOG << "CREATING stage" << node_->ToString() << "node" << node_;
    }

    void Execute() {
        LOG << "EXECUTING stage " << node_->ToString() << "node" << node_;
        node_->Execute();
        node_->UnregisterChilds();
        node_->set_state(c7a::api::EXECUTED);
    }

    void PushData() {
        LOG << "PUSHING stage " << node_->ToString() << "node" << node_;
        node_->PushData();
    }

    void Dispose() {
        LOG << "DISPOSING stage " << node_->ToString() << "node" << node_;
        node_->Dispose();
        node_->set_state(c7a::api::DISPOSED);
    }

    DIABase * node() {
        return node_;
    }

private:
    static const bool debug = false;
    DIABase* node_;
};

class StageBuilder
{
public:
    void FindStages(DIABase* action, std::vector<Stage>& stages_result) {
        LOG << "FINDING stages:";
        // std::set<const DIABase*> stages_found;
        std::vector<DIABase*> stages_found;
        // Do a reverse DFS and find all stages
        std::stack<DIABase*> dia_stack;
        dia_stack.push(action);
        // stages_found.insert(action);
        stages_found.push_back(action);
        while (!dia_stack.empty()) {
            DIABase* curr = dia_stack.top();
            dia_stack.pop();
            const auto parents = curr->parents();
            for (size_t i = 0; i < parents.size(); ++i) {
                auto p = parents[i].get();
                stages_found.push_back(p);
                if (p->state() != c7a::api::EXECUTED) {
                    dia_stack.push(p);
                }
            }
        }
        for (auto stage : stages_found) {
            stages_result.emplace_back(stage);
        }
        std::reverse(stages_result.begin(), stages_result.end());
    }

    void RunScope(DIABase* action) {
        std::vector<Stage> result;
        FindStages(action, result);
        for (auto s : result)
        {
            // TODO(sl): This is nonsense -tb, fix it:
            if (s.node()->state() == c7a::api::EXECUTED) s.Execute();
            if (s.node()->state() == c7a::api::EXECUTED) s.PushData();
        }
    }

    static const bool debug = false;
};

} // namespace core
} // namespace c7a

#endif // !C7A_CORE_STAGE_BUILDER_HEADER

/******************************************************************************/
<commit_msg>Fixed all except Zip.<commit_after>/*******************************************************************************
 * c7a/core/stage_builder.hpp
 *
 * Part of Project c7a.
 *
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_CORE_STAGE_BUILDER_HEADER
#define C7A_CORE_STAGE_BUILDER_HEADER

#include <c7a/api/dia_base.hpp>
#include <c7a/common/logger.hpp>

#include <algorithm>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>

namespace c7a {
namespace core {

using c7a::api::DIABase;

class Stage
{
public:
    explicit Stage(DIABase* node) : node_(node) {
        LOG << "CREATING stage" << node_->ToString() << "node" << node_;
    }

    void Execute() {
        LOG << "EXECUTING stage " << node_->ToString() << "node" << node_;
        node_->Execute();
        node_->PushData();
        node_->UnregisterChilds();
        node_->set_state(c7a::api::EXECUTED);
    }

    void PushData() {
        LOG << "PUSHING stage " << node_->ToString() << "node" << node_;
        node_->PushData();
    }

    void Dispose() {
        LOG << "DISPOSING stage " << node_->ToString() << "node" << node_;
        node_->Dispose();
        node_->set_state(c7a::api::DISPOSED);
    }

    DIABase * node() {
        return node_;
    }

private:
    static const bool debug = false;
    DIABase* node_;
};

class StageBuilder
{
public:
    void FindStages(DIABase* action, std::vector<Stage>& stages_result) {
        LOG << "FINDING stages:";
        // std::set<const DIABase*> stages_found;
        std::vector<DIABase*> stages_found;
        // Do a reverse DFS and find all stages
        std::stack<DIABase*> dia_stack;
        dia_stack.push(action);
        // stages_found.insert(action);
        stages_found.push_back(action);
        while (!dia_stack.empty()) {
            DIABase* curr = dia_stack.top();
            dia_stack.pop();
            const auto parents = curr->parents();
            for (size_t i = 0; i < parents.size(); ++i) {
                auto p = parents[i].get();
                stages_found.push_back(p);
                if (p->state() != c7a::api::EXECUTED) {
                    dia_stack.push(p);
                }
            }
        }
        for (auto stage : stages_found) {
            stages_result.emplace_back(stage);
        }
        std::reverse(stages_result.begin(), stages_result.end());
    }

    void RunScope(DIABase* action) {
        std::vector<Stage> result;
        FindStages(action, result);
        for (auto s : result)
        {
            // TODO(sl): This is nonsense -tb, fix it:
            if (s.node()->state() == c7a::api::EXECUTED) s.PushData();
            if (s.node()->state() == c7a::api::NEW) s.Execute();
        }
    }

    static const bool debug = false;
};

} // namespace core
} // namespace c7a

#endif // !C7A_CORE_STAGE_BUILDER_HEADER

/******************************************************************************/
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "Exception.h"
#include "Backtrace.h"
#include "Logger.h"
#include "OSHelper.h"

#include <cstdlib>
#include <sstream>

using namespace std;

namespace avg {

Exception::Exception(int code, const string& sErr)
    : std::exception(),
      m_Code (code),
      m_sErr (sErr)
{
}

Exception::Exception(const Exception& ex)
    : std::exception(),
      m_Code (ex.getCode()),
      m_sErr (ex.getStr())
{
}

Exception::~Exception() throw()
{
}

int Exception::getCode() const
{
    return m_Code;
}

const string& Exception::getStr() const
{
    return m_sErr;
}

const char* Exception::what() const throw()
{
    return m_sErr.c_str();
}

void fatalError(const string& sMsg, int type)
{
    AVG_LOG_ERROR("Internal error: "+sMsg+" Aborting.");
    throw(Exception(type, sMsg));
}

void debugBreak()
{
#ifdef _WIN32
    __asm int 3;
#else
    __builtin_trap();
#endif
}

void avgAssert(bool b, const char * pszFile, int line, const char * pszReason)
{
    if (!b) {
        string sDummy;
        static bool bBreak = getEnv("AVG_BREAK_ON_ASSERT", sDummy);
        if (bBreak) {
            debugBreak();
        } else {
            stringstream ss;
            ss << "Assertion failed in " << pszFile << ": " << line << endl;
            if (pszReason) {
                ss << "Reason: " << pszReason << endl;
            }
            dumpBacktrace();
            throw(Exception(AVG_ERR_ASSERT_FAILED, ss.str()));
        }
    }
}

}
<commit_msg>Replaced __asm with __debugbreak, work on #384<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "Exception.h"
#include "Backtrace.h"
#include "Logger.h"
#include "OSHelper.h"

#include <cstdlib>
#include <sstream>

#ifdef WIN32
#include <intrin.h>
#endif

using namespace std;

namespace avg {

Exception::Exception(int code, const string& sErr)
    : std::exception(),
      m_Code (code),
      m_sErr (sErr)
{
}

Exception::Exception(const Exception& ex)
    : std::exception(),
      m_Code (ex.getCode()),
      m_sErr (ex.getStr())
{
}

Exception::~Exception() throw()
{
}

int Exception::getCode() const
{
    return m_Code;
}

const string& Exception::getStr() const
{
    return m_sErr;
}

const char* Exception::what() const throw()
{
    return m_sErr.c_str();
}

void fatalError(const string& sMsg, int type)
{
    AVG_LOG_ERROR("Internal error: "+sMsg+" Aborting.");
    throw(Exception(type, sMsg));
}

void debugBreak()
{
#ifdef _WIN32
    __debugbreak();
#else
    __builtin_trap();
#endif
}

void avgAssert(bool b, const char * pszFile, int line, const char * pszReason)
{
    if (!b) {
        string sDummy;
        static bool bBreak = getEnv("AVG_BREAK_ON_ASSERT", sDummy);
        if (bBreak) {
            debugBreak();
        } else {
            stringstream ss;
            ss << "Assertion failed in " << pszFile << ": " << line << endl;
            if (pszReason) {
                ss << "Reason: " << pszReason << endl;
            }
            dumpBacktrace();
            throw(Exception(AVG_ERR_ASSERT_FAILED, ss.str()));
        }
    }
}

}
<|endoftext|>


<commit_before>#ifndef AMGCL_SOLVERS_CG_HPP
#define AMGCL_SOLVERS_CG_HPP

/*
The MIT License

Copyright (c) 2012-2015 Denis Demidov <dennis.demidov@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   amgcl/solver/cg.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Conjugate Gradient method.
 */

#include <boost/tuple/tuple.hpp>
#include <amgcl/backend/interface.hpp>
#include <amgcl/solver/detail/default_inner_product.hpp>
#include <amgcl/util.hpp>

namespace amgcl {

/// Iterative solvers
namespace solver {

/**
 * \defgroup solvers
 * \brief Iterative solvers
 *
 * AMGCL provides several iterative solvers, but it should be easy to use it as
 * a preconditioner with a user-provided solver.  Each solver in AMGCL is a
 * class template. Its single template parameter specifies the backend to use.
 * This allows to preallocate necessary resources at class construction.
 * Obviously, the solver backend has to coincide with the AMG backend.
 */

/// Conjugate Gradients iterative solver.
/**
 * \param Backend Backend for temporary structures allocation.
 * \ingroup solvers
 * \sa \cite Barrett1994
 */
template <
    class Backend,
    class InnerProduct = detail::default_inner_product
    >
class cg {
    public:
        typedef Backend backend_type;

        typedef typename Backend::vector     vector;
        typedef typename Backend::value_type value_type;
        typedef typename Backend::params     backend_params;

        typedef typename math::scalar_of<value_type>::type scalar_type;

        typedef typename math::inner_product_impl<
            typename math::rhs_of<value_type>::type
            >::return_type coef_type;

        /// Solver parameters.
        struct params {
            /// Maximum number of iterations.
            size_t maxiter;

            /// Target residual error.
            scalar_type tol;

            params(size_t maxiter = 100, scalar_type tol = 1e-8)
                : maxiter(maxiter), tol(tol)
            {}

            params(const boost::property_tree::ptree &p)
                : AMGCL_PARAMS_IMPORT_VALUE(p, maxiter),
                  AMGCL_PARAMS_IMPORT_VALUE(p, tol)
            {}

            void get(boost::property_tree::ptree &p, const std::string &path) const {
                AMGCL_PARAMS_EXPORT_VALUE(p, path, maxiter);
                AMGCL_PARAMS_EXPORT_VALUE(p, path, tol);
            }
        };

        /// Preallocates necessary data structures
        /**
         * \param n           The system size.
         * \param prm         Solver parameters.
         * \param backend_prm Backend parameters.
         */
        cg(
                size_t n,
                const params &prm = params(),
                const backend_params &backend_prm = backend_params(),
                const InnerProduct &inner_product = InnerProduct()
          ) : prm(prm), n(n),
              r(Backend::create_vector(n, backend_prm)),
              s(Backend::create_vector(n, backend_prm)),
              p(Backend::create_vector(n, backend_prm)),
              q(Backend::create_vector(n, backend_prm)),
              inner_product(inner_product)
        { }

        /// Solves the linear system for the given system matrix.
        /**
         * \param A   System matrix.
         * \param P   Preconditioner.
         * \param rhs Right-hand side.
         * \param x   Solution vector.
         *
         * The system matrix may differ from the matrix used for the AMG
         * preconditioner construction. This may be used for the solution of
         * non-stationary problems with slowly changing coefficients. There is
         * a strong chance that AMG built for one time step will act as a
         * reasonably good preconditioner for several subsequent time steps
         * \cite Demidov2012.
         */
        template <class Matrix, class Precond, class Vec1, class Vec2>
        boost::tuple<size_t, scalar_type> operator()(
                Matrix  const &A,
                Precond const &P,
                Vec1    const &rhs,
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
                Vec2          &x
#else
                Vec2          &&x
#endif
                ) const
        {
            static const coef_type one  = math::identity<coef_type>();
            static const coef_type zero = math::zero<coef_type>();

            backend::residual(rhs, A, x, *r);
            scalar_type norm_rhs = norm(rhs);
            if (norm_rhs < amgcl::detail::eps<scalar_type>(n)) {
                backend::clear(x);
                return boost::make_tuple(0, norm_rhs);
            }

            scalar_type eps  = prm.tol * norm_rhs;
            scalar_type eps2 = eps * eps;

            coef_type rho1 = 2 * eps2 * one;
            coef_type rho2 = zero;
            scalar_type res_norm = norm(*r);

            size_t iter = 0;
            for(; iter < prm.maxiter && math::norm(rho1) > eps2; ++iter) {
                P.apply(*r, *s);

                rho2 = rho1;
                rho1 = inner_product(*r, *s);

                if (iter)
                    backend::axpby(one, *s, rho1 / rho2, *p);
                else
                    backend::copy(*s, *p);

                backend::spmv(one, A, *p, zero, *q);

                coef_type alpha = rho1 / inner_product(*q, *p);

                backend::axpby( alpha, *p, one,  x);
                backend::axpby(-alpha, *q, one, *r);
            }

            backend::residual(rhs, A, x, *r);
            res_norm = norm(*r);

            return boost::make_tuple(iter, res_norm / norm_rhs);
        }

        /// Solves the linear system for the same matrix that was used for the AMG preconditioner construction.
        /**
         * \param P   AMG preconditioner.
         * \param rhs Right-hand side.
         * \param x   Solution vector.
         */
        template <class Precond, class Vec1, class Vec2>
        boost::tuple<size_t, scalar_type> operator()(
                Precond const &P,
                Vec1    const &rhs,
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
                Vec2          &x
#else
                Vec2          &&x
#endif
                ) const
        {
            return (*this)(P.system_matrix(), P, rhs, x);
        }

    public:
        params prm;

    private:
        size_t n;

        boost::shared_ptr<vector> r;
        boost::shared_ptr<vector> s;
        boost::shared_ptr<vector> p;
        boost::shared_ptr<vector> q;

        InnerProduct inner_product;

        template <class Vec>
        scalar_type norm(const Vec &x) const {
            return sqrt(math::norm(inner_product(x, x)));
        }
};

} // namespace solver
} // namespace amgcl

#endif
<commit_msg>More robust exit condition in solver::cg<commit_after>#ifndef AMGCL_SOLVERS_CG_HPP
#define AMGCL_SOLVERS_CG_HPP

/*
The MIT License

Copyright (c) 2012-2015 Denis Demidov <dennis.demidov@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   amgcl/solver/cg.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Conjugate Gradient method.
 */

#include <boost/tuple/tuple.hpp>
#include <amgcl/backend/interface.hpp>
#include <amgcl/solver/detail/default_inner_product.hpp>
#include <amgcl/util.hpp>

namespace amgcl {

/// Iterative solvers
namespace solver {

/**
 * \defgroup solvers
 * \brief Iterative solvers
 *
 * AMGCL provides several iterative solvers, but it should be easy to use it as
 * a preconditioner with a user-provided solver.  Each solver in AMGCL is a
 * class template. Its single template parameter specifies the backend to use.
 * This allows to preallocate necessary resources at class construction.
 * Obviously, the solver backend has to coincide with the AMG backend.
 */

/// Conjugate Gradients iterative solver.
/**
 * \param Backend Backend for temporary structures allocation.
 * \ingroup solvers
 * \sa \cite Barrett1994
 */
template <
    class Backend,
    class InnerProduct = detail::default_inner_product
    >
class cg {
    public:
        typedef Backend backend_type;

        typedef typename Backend::vector     vector;
        typedef typename Backend::value_type value_type;
        typedef typename Backend::params     backend_params;

        typedef typename math::scalar_of<value_type>::type scalar_type;

        typedef typename math::inner_product_impl<
            typename math::rhs_of<value_type>::type
            >::return_type coef_type;

        /// Solver parameters.
        struct params {
            /// Maximum number of iterations.
            size_t maxiter;

            /// Target residual error.
            scalar_type tol;

            params(size_t maxiter = 100, scalar_type tol = 1e-8)
                : maxiter(maxiter), tol(tol)
            {}

            params(const boost::property_tree::ptree &p)
                : AMGCL_PARAMS_IMPORT_VALUE(p, maxiter),
                  AMGCL_PARAMS_IMPORT_VALUE(p, tol)
            {}

            void get(boost::property_tree::ptree &p, const std::string &path) const {
                AMGCL_PARAMS_EXPORT_VALUE(p, path, maxiter);
                AMGCL_PARAMS_EXPORT_VALUE(p, path, tol);
            }
        };

        /// Preallocates necessary data structures
        /**
         * \param n           The system size.
         * \param prm         Solver parameters.
         * \param backend_prm Backend parameters.
         */
        cg(
                size_t n,
                const params &prm = params(),
                const backend_params &backend_prm = backend_params(),
                const InnerProduct &inner_product = InnerProduct()
          ) : prm(prm), n(n),
              r(Backend::create_vector(n, backend_prm)),
              s(Backend::create_vector(n, backend_prm)),
              p(Backend::create_vector(n, backend_prm)),
              q(Backend::create_vector(n, backend_prm)),
              inner_product(inner_product)
        { }

        /// Solves the linear system for the given system matrix.
        /**
         * \param A   System matrix.
         * \param P   Preconditioner.
         * \param rhs Right-hand side.
         * \param x   Solution vector.
         *
         * The system matrix may differ from the matrix used for the AMG
         * preconditioner construction. This may be used for the solution of
         * non-stationary problems with slowly changing coefficients. There is
         * a strong chance that AMG built for one time step will act as a
         * reasonably good preconditioner for several subsequent time steps
         * \cite Demidov2012.
         */
        template <class Matrix, class Precond, class Vec1, class Vec2>
        boost::tuple<size_t, scalar_type> operator()(
                Matrix  const &A,
                Precond const &P,
                Vec1    const &rhs,
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
                Vec2          &x
#else
                Vec2          &&x
#endif
                ) const
        {
            static const coef_type one  = math::identity<coef_type>();
            static const coef_type zero = math::zero<coef_type>();

            backend::residual(rhs, A, x, *r);
            scalar_type norm_rhs = norm(rhs);
            if (norm_rhs < amgcl::detail::eps<scalar_type>(n)) {
                backend::clear(x);
                return boost::make_tuple(0, norm_rhs);
            }

            scalar_type eps  = prm.tol * norm_rhs;
            scalar_type eps2 = eps * eps;

            coef_type rho1 = 2 * eps2 * one;
            coef_type rho2 = zero;
            scalar_type res_norm = norm(*r);

            size_t iter = 0;
            for(; iter < prm.maxiter && math::norm(res_norm) > eps2; ++iter) {
                P.apply(*r, *s);

                rho2 = rho1;
                rho1 = inner_product(*r, *s);

                if (iter)
                    backend::axpby(one, *s, rho1 / rho2, *p);
                else
                    backend::copy(*s, *p);

                backend::spmv(one, A, *p, zero, *q);

                coef_type alpha = rho1 / inner_product(*q, *p);

                backend::axpby( alpha, *p, one,  x);
                backend::axpby(-alpha, *q, one, *r);

                res_norm = norm(*r);
            }

            backend::residual(rhs, A, x, *r);
            res_norm = norm(*r);

            return boost::make_tuple(iter, res_norm / norm_rhs);
        }

        /// Solves the linear system for the same matrix that was used for the AMG preconditioner construction.
        /**
         * \param P   AMG preconditioner.
         * \param rhs Right-hand side.
         * \param x   Solution vector.
         */
        template <class Precond, class Vec1, class Vec2>
        boost::tuple<size_t, scalar_type> operator()(
                Precond const &P,
                Vec1    const &rhs,
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
                Vec2          &x
#else
                Vec2          &&x
#endif
                ) const
        {
            return (*this)(P.system_matrix(), P, rhs, x);
        }

    public:
        params prm;

    private:
        size_t n;

        boost::shared_ptr<vector> r;
        boost::shared_ptr<vector> s;
        boost::shared_ptr<vector> p;
        boost::shared_ptr<vector> q;

        InnerProduct inner_product;

        template <class Vec>
        scalar_type norm(const Vec &x) const {
            return sqrt(math::norm(inner_product(x, x)));
        }
};

} // namespace solver
} // namespace amgcl

#endif
<|endoftext|>