<commit_before>#include <unistd.h>
#include <iostream>
#include <exception>
#include <algorithm>
#include <memory>
#include "procinfo.h"
#include "elfinfo.h"
#include "dwarf.h"

using namespace std;

extern "C" {
#include "proc_service.h"
}

static int
globmatchR(const char *pattern, const char *name)
{
    for (;; name++) {
        switch (*pattern) {
        case '*':
            // if the rest of the name matches the bit of pattern after '*',
            for (;;) {
                ++name;
                if (globmatchR(pattern + 1, name))
                    return 1;
                if (*name == 0) // exhuasted name without finding a match
                    return 0;
            }
        default:
            if (*name != *pattern)
                return 0;
        }
        if (*pattern++ == 0)
            return 1;
    }
}

static int
globmatch(string pattern, string name)
{
    return globmatchR(pattern.c_str(), name.c_str());
}

struct ListedSymbol {
    Elf_Sym sym;
    Elf_Off objbase;
    string objname;
    size_t count;
    string name;
    ListedSymbol(const Elf_Sym &sym_, Elf_Off objbase_, string name_, string object)
        : sym(sym_)
        , objbase(objbase_)
        , name(name_)
        , count(0)
        , objname(object)

    {
    }
    Elf_Off memaddr() const { return  sym.st_value + objbase; }
};

const bool operator < (const ListedSymbol &sym, Elf_Off addr) {
    return sym.memaddr() + sym.sym.st_size < addr;
}

struct Symcounter {
    Elf_Off addr;
    string name;
    unsigned count;
    struct ListedSymbol *sym;
};

vector<Symcounter> counters;

static const char *virtpattern = "_ZTV*"; /* wildcard for all vtbls */

int
mainExcept(int argc, char *argv[])
{
    bool findRef = false;
    shared_ptr<ElfObject> exec;
    shared_ptr<ElfObject> core;
    shared_ptr<Process> process;
    int c;
    int verbose = 0;
    bool showaddrs = false;

    Elf_Off minval, maxval;
    char *strbuf = 0;
    char *findstr = 0;
    size_t findstrlen;

    while ((c = getopt(argc, argv, "vhsp:f:e:S:")) != -1) {
        switch (c) {
            case 'p':
                virtpattern = optarg;
                break;
            case 's':
                showaddrs = true;
                break;
            case 'v':
                debug = &clog;
                verbose++;
                break;
            case 'h':
                clog << "usage: canal [exec] <core>" << endl;
                return 0;
            case 'S':
                findstr = optarg;
                findstrlen = strlen(findstr);
                strbuf = new char[findstrlen];
                break;

            case 'f':
                findRef = true;
                maxval = minval = strtoll(optarg, 0, 0);
                break;

            case 'e':
                if (!findRef)
                    abort();
                maxval = strtoll(optarg, 0, 0);
                break;

            case 'X':
                ps_lgetfpregs(0, 0, 0);
        }
    }

    if (argc - optind >= 2) {
        auto file = make_shared<FileReader>(argv[optind]);
        // It's a file:
        exec = make_shared<ElfObject>(file);
        optind++;
    }

    if (argc - optind >= 1) {
        char *eoa;
        pid_t pid = strtol(argv[optind], &eoa, 10);
        core = make_shared<ElfObject>(make_shared<FileReader>(argv[optind]));
        process = make_shared<CoreProcess>(exec, core);
    }
    process->load();
    if (findRef) {
        std::clog << "finding references to addresses from " << hex << minval << " to " << maxval << "\n";
    }
    clog << "opened process " << process << endl;

    vector<ListedSymbol> listed;
    for (auto &loaded : process->objects) {
        size_t count = 0;
        for (const auto sym : loaded.object->getSymbols(".dynsym")) {
            if (globmatch(virtpattern, sym.second)) {
                listed.push_back(ListedSymbol(sym.first, loaded.reloc, sym.second, loaded.object->io->describe()));
                count++;
            }
        }
        if (debug)
            *debug << "found " << count << " symbols in " << loaded.object->io->describe() << endl;
    }
    sort(listed.begin()
        , listed.end()
        , [] (const ListedSymbol &l, const ListedSymbol &r) { return l.memaddr() < r.memaddr(); });

    // Now run through the corefile, searching for virtual objects.
    off_t filesize = 0;
    off_t memsize = 0;
    for (auto hdr : core->getSegments()) {
        if (hdr.p_type != PT_LOAD)
            continue;
        Elf_Off p;
        filesize += hdr.p_filesz;
        memsize += hdr.p_memsz;
        if (debug) {
            *debug << "scan " << hex << hdr.p_vaddr <<  " to " << hdr.p_vaddr + hdr.p_memsz << " ";
            *debug << "(filesiz = " << hdr.p_filesz  << ", memsiz=" << hdr.p_memsz << ") ";
        }

        if (findstr) {
            for (auto loc = hdr.p_vaddr; loc < hdr.p_vaddr + hdr.p_filesz - findstrlen; loc++) {
                size_t rc = process->io->read(loc, findstrlen, strbuf);
                if (memcmp(strbuf, findstr, findstrlen) == 0)
                    std::cout << "0x" << hex << loc << "\n";
            }
        } else {

            for (auto loc = hdr.p_vaddr; loc < hdr.p_vaddr + hdr.p_filesz; loc += sizeof p) {
                if (verbose && (loc - hdr.p_vaddr) % (1024 * 1024) == 0)
                    clog << '.';
                process->io->readObj(loc, &p);
                if (findRef) {
                    if (p >= minval && p < maxval && (p % 4 == 0))
                        cout << "0x" << hex << loc << "\n";
                } else {
                    auto found = lower_bound(listed.begin(), listed.end(), p);
                    if (found != listed.end() && found->memaddr() <= p && found->memaddr() + found->sym.st_size > p) {
                        if (showaddrs)
                            cout << found->name << " " << loc << endl;
                        found->count++;
                    }
                }
            }
        }

        if (debug)
            *debug << endl;

    }
    if (debug)
        *debug << "core file contains " << filesize << " out of " << memsize << " bytes of memory\n";

    sort(listed.begin()
        , listed.end()
        , [] (const ListedSymbol &l, const ListedSymbol &r) { return l.count > r.count; });

    for (auto &i : listed)
        if (i.count)
            cout << dec << i.count << " " << i.name << " ( from " << i.objname << ")" << endl;
    return 0;
}

int
main(int argc, char *argv[])
{
    try {
        return mainExcept(argc, argv);
    }
    catch (const exception &ex) {
        cerr << "exception: " << ex.what() << endl;
        return -1;
    }
}
<commit_msg>Use string-based construction to get caching.<commit_after>#include <unistd.h>
#include <iostream>
#include <exception>
#include <algorithm>
#include <memory>
#include "procinfo.h"
#include "elfinfo.h"
#include "dwarf.h"

using namespace std;

extern "C" {
#include "proc_service.h"
}

static int
globmatchR(const char *pattern, const char *name)
{
    for (;; name++) {
        switch (*pattern) {
        case '*':
            // if the rest of the name matches the bit of pattern after '*',
            for (;;) {
                ++name;
                if (globmatchR(pattern + 1, name))
                    return 1;
                if (*name == 0) // exhuasted name without finding a match
                    return 0;
            }
        default:
            if (*name != *pattern)
                return 0;
        }
        if (*pattern++ == 0)
            return 1;
    }
}

static int
globmatch(string pattern, string name)
{
    return globmatchR(pattern.c_str(), name.c_str());
}

struct ListedSymbol {
    Elf_Sym sym;
    Elf_Off objbase;
    string objname;
    size_t count;
    string name;
    ListedSymbol(const Elf_Sym &sym_, Elf_Off objbase_, string name_, string object)
        : sym(sym_)
        , objbase(objbase_)
        , name(name_)
        , count(0)
        , objname(object)

    {
    }
    Elf_Off memaddr() const { return  sym.st_value + objbase; }
};

const bool operator < (const ListedSymbol &sym, Elf_Off addr) {
    return sym.memaddr() + sym.sym.st_size < addr;
}

struct Symcounter {
    Elf_Off addr;
    string name;
    unsigned count;
    struct ListedSymbol *sym;
};

vector<Symcounter> counters;

static const char *virtpattern = "_ZTV*"; /* wildcard for all vtbls */

int
mainExcept(int argc, char *argv[])
{
    bool findRef = false;
    shared_ptr<ElfObject> exec;
    shared_ptr<ElfObject> core;
    shared_ptr<Process> process;
    int c;
    int verbose = 0;
    bool showaddrs = false;

    Elf_Off minval, maxval;
    char *strbuf = 0;
    char *findstr = 0;
    size_t findstrlen;

    while ((c = getopt(argc, argv, "vhsp:f:e:S:")) != -1) {
        switch (c) {
            case 'p':
                virtpattern = optarg;
                break;
            case 's':
                showaddrs = true;
                break;
            case 'v':
                debug = &clog;
                verbose++;
                break;
            case 'h':
                clog << "usage: canal [exec] <core>" << endl;
                return 0;
            case 'S':
                findstr = optarg;
                findstrlen = strlen(findstr);
                strbuf = new char[findstrlen];
                break;

            case 'f':
                findRef = true;
                maxval = minval = strtoll(optarg, 0, 0);
                break;

            case 'e':
                if (!findRef)
                    abort();
                maxval = strtoll(optarg, 0, 0);
                break;

            case 'X':
                ps_lgetfpregs(0, 0, 0);
        }
    }

    if (argc - optind >= 2) {
        exec = make_shared<ElfObject>(argv[optind]);
        optind++;
    }

    if (argc - optind >= 1) {
        char *eoa;
        pid_t pid = strtol(argv[optind], &eoa, 10);
        core = make_shared<ElfObject>(argv[optind]);
        process = make_shared<CoreProcess>(exec, core);
    }
    process->load();
    if (findRef) {
        std::clog << "finding references to addresses from " << hex << minval << " to " << maxval << "\n";
    }
    clog << "opened process " << process << endl;

    vector<ListedSymbol> listed;
    for (auto &loaded : process->objects) {
        size_t count = 0;
        for (const auto sym : loaded.object->getSymbols(".dynsym")) {
            if (globmatch(virtpattern, sym.second)) {
                listed.push_back(ListedSymbol(sym.first, loaded.reloc, sym.second, loaded.object->io->describe()));
                count++;
            }
        }
        if (debug)
            *debug << "found " << count << " symbols in " << loaded.object->io->describe() << endl;
    }
    sort(listed.begin()
        , listed.end()
        , [] (const ListedSymbol &l, const ListedSymbol &r) { return l.memaddr() < r.memaddr(); });

    // Now run through the corefile, searching for virtual objects.
    off_t filesize = 0;
    off_t memsize = 0;
    for (auto hdr : core->getSegments()) {
        if (hdr.p_type != PT_LOAD)
            continue;
        Elf_Off p;
        filesize += hdr.p_filesz;
        memsize += hdr.p_memsz;
        if (debug) {
            *debug << "scan " << hex << hdr.p_vaddr <<  " to " << hdr.p_vaddr + hdr.p_memsz << " ";
            *debug << "(filesiz = " << hdr.p_filesz  << ", memsiz=" << hdr.p_memsz << ") ";
        }

        if (findstr) {
            for (auto loc = hdr.p_vaddr; loc < hdr.p_vaddr + hdr.p_filesz - findstrlen; loc++) {
                size_t rc = process->io->read(loc, findstrlen, strbuf);
                if (memcmp(strbuf, findstr, findstrlen) == 0)
                    std::cout << "0x" << hex << loc << "\n";
            }
        } else {

            for (auto loc = hdr.p_vaddr; loc < hdr.p_vaddr + hdr.p_filesz; loc += sizeof p) {
                if (verbose && (loc - hdr.p_vaddr) % (1024 * 1024) == 0)
                    clog << '.';
                process->io->readObj(loc, &p);
                if (findRef) {
                    if (p >= minval && p < maxval && (p % 4 == 0))
                        cout << "0x" << hex << loc << "\n";
                } else {
                    auto found = lower_bound(listed.begin(), listed.end(), p);
                    if (found != listed.end() && found->memaddr() <= p && found->memaddr() + found->sym.st_size > p) {
                        if (showaddrs)
                            cout << found->name << " " << loc << endl;
                        found->count++;
                    }
                }
            }
        }

        if (debug)
            *debug << endl;

    }
    if (debug)
        *debug << "core file contains " << filesize << " out of " << memsize << " bytes of memory\n";

    sort(listed.begin()
        , listed.end()
        , [] (const ListedSymbol &l, const ListedSymbol &r) { return l.count > r.count; });

    for (auto &i : listed)
        if (i.count)
            cout << dec << i.count << " " << i.name << " ( from " << i.objname << ")" << endl;
    return 0;
}

int
main(int argc, char *argv[])
{
    try {
        return mainExcept(argc, argv);
    }
    catch (const exception &ex) {
        cerr << "exception: " << ex.what() << endl;
        return -1;
    }
}
<|endoftext|>


<commit_before>#ifndef HMLIB_ODEINT_INC
#define HMLIB_ODEINT_INC 100
#
#include"odeint/break_observer.hpp"
#
#endif
<commit_msg>Add include of new odeint files in odeint.hpp.<commit_after>#ifndef HMLIB_ODEINT_INC
#define HMLIB_ODEINT_INC 100
#
#include"odeint/break_observer.hpp"
#include"odeint/breakable_integrate.hpp"
#include"odeint/container_observer.hpp"
#include"odeint/eqstate_break_observer.hpp"
#include"odeint/iterator_observer.hpp"
#include"odeint/range_stepper.hpp"
#include"odeint/stream_observer.hpp"
#
#endif
<|endoftext|>


<commit_before>/*
 * uart-cdc-dev.cpp
 *
 * Copyright (c) 2018 Lix N. Paulian (lix@paulian.net)
 *
 * 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.
 *
 * Created on: 13 Jan 2018 (LNP)
 */

#include <cmsis-plus/rtos/os.h>
#include <cmsis-plus/diag/trace.h>

#include <uart-cdc-dev.h>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"

namespace os
{
  namespace driver
  {
    namespace stm32f7
    {

      uart_cdc_dev::uart_cdc_dev (const char* name, uint8_t usb_id, uint8_t* tx_buff,
                          uint8_t* rx_buff, size_t tx_buff_size,
                          size_t rx_buff_size) : //
          tty
            { name }, //
          usb_id_
            { usb_id }, //
          tx_buff_
            { tx_buff }, //
          rx_buff_
            { rx_buff }, //
          tx_buff_size_
            { tx_buff_size }, //
          rx_buff_size_
            { rx_buff_size }
      {
        trace::printf ("%s() %p\n", __func__, this);
      }

      uart_cdc_dev::~uart_cdc_dev ()
      {
        trace::printf ("%s() %p\n", __func__, this);

        is_opened_ = false;
      }

      int
      uart_cdc_dev::do_vopen (const char* path, int oflag, std::va_list args)
      {
        int result = -1;

        do
          {
            if (is_opened_)
              {
                errno = EEXIST; // already opened
                break;
              }

            // initialize FIFOs and semaphores
            rx_in_ = rx_out_ = 0;

            // reset semaphores
            init_sem_.reset ();
            rx_sem_.reset ();

            // initialize the USB peripheral
            if ((husbd_ = USB_DEVICE_Init (usb_id_)) == nullptr)
              {
                errno = EIO;
                break;
              }

            // if no rx/tx static buffers supplied, create them dynamically
            if (tx_buff_ == nullptr)
              {
                if ((tx_buff_ = new uint8_t[tx_buff_size_]) == nullptr)
                  {
                    errno = ENOMEM;
                    break;
                  }
                else
                  {
                    tx_buff_dyn_ = true;
                  }
              }
            else
              {
                tx_buff_dyn_ = false;
              }

            if (rx_buff_ == nullptr)
              {
                if ((rx_buff_ = new uint8_t[rx_buff_size_]) == nullptr)
                  {
                    if (tx_buff_dyn_ == true)
                      {
                        delete[] tx_buff_;
                        tx_buff_ = nullptr;
                      }
                    errno = ENOMEM;
                    break;
                  }
                else
                  {
                    rx_buff_dyn_ = true;
                  }
              }
            else
              {
                rx_buff_dyn_ = false;
              }

            // set initial timeout depending on the O_NONBLOCK flag
            if (oflag & O_NONBLOCK)
              {
                rx_timeout_ = 0x0;
                o_nonblock_ = true;
              }
            else
              {
                rx_timeout_ = 0xFFFFFFFF;
                o_nonblock_ = false;
              }

            // wait for the usb device initialization to complete
            init_sem_.wait ();

            if ((cdc_buff_ = new uint8_t[packet_size_]) == nullptr)
              {
                if (tx_buff_dyn_ == true)
                  {
                    delete[] tx_buff_;
                    tx_buff_ = nullptr;
                  }
                if (rx_buff_dyn_ == true)
                  {
                    delete[] rx_buff_;
                    rx_buff_ = nullptr;
                  }
                errno = ENOMEM;
                break;
              }

            is_opened_ = true;
            result = 0;

            // start receiving, basically wait for input characters
            USBD_CDC_SetRxBuffer (husbd_, cdc_buff_);
            USBD_CDC_ReceivePacket (husbd_);
          }
        while (false);

        return result;
      }

      int
      uart_cdc_dev::do_close (void)
      {
        // wait for potential ongoing write operation to finish
        if (husbd_ != nullptr)
          {
            USBD_CDC_HandleTypeDef* pcd =
                (USBD_CDC_HandleTypeDef*) husbd_->pClassData;
            int count = 100;      // 100 ms timeout
            while (pcd->TxState != 0 && count--)
              {
                // busy, wait
                rtos::sysclock.sleep_for (1);
              }
          }
        // shut down the USB peripheral
        USBD_DeInit (husbd_);

        // clean-up dynamic allocations, if any
        if (tx_buff_dyn_ == true)
          {
            delete[] tx_buff_;
            tx_buff_ = nullptr;
          }

        if (rx_buff_dyn_ == true)
          {
            delete[] rx_buff_;
            rx_buff_ = nullptr;
          }

        delete[] cdc_buff_;

        is_opened_ = false;

        return 0;
      }

      ssize_t
      uart_cdc_dev::do_read (void* buf, std::size_t nbyte)
      {
        uint8_t* lbuf = (uint8_t *) buf;
        ssize_t count = 0;

        os::rtos::clock::duration_t timeout =
            o_nonblock_ ? 0 : (cc_vmin_ > 0) ? 0xFFFFFFFF : rx_timeout_;

        uint32_t last_count = rx_in_;

        do
          {
            while (rx_out_ == rx_in_)
              {
                if (rx_sem_.timed_wait (timeout) != os::rtos::result::ok)
                  {
                    if (last_count == rx_in_)
                      {
                        // no more chars received: that means inter-char timeout
                        // return number of chars collected, if any
                        break;
                      }
                    last_count = rx_in_;
                  }
                if (is_error_ == true)
                  {
                    is_error_ = false;
                    errno = EIO;
                    return -1;  // an error was reported, exit
                  }
              }

            // retrieve accumulated chars, if any
            while (rx_out_ != rx_in_ && count < (ssize_t) nbyte)
              {
                *lbuf++ = rx_buff_[rx_out_++];
                if (++count == 1)
                  {
                    // VMIN > 0, apply timeout (can be infinitum too)
                    timeout = rx_timeout_;
                  }
                if (rx_out_ >= rx_buff_size_)
                  {
                    rx_out_ = 0;
                  }
              }   // TODO: check and wait for last packet condition
          }
        while (count < cc_vmin_);

        return count;
      }

      ssize_t
      uart_cdc_dev::do_write (const void* buf, std::size_t nbyte)
      {
        USBD_StatusTypeDef result;
        uint8_t* p = (uint8_t*) buf;
        ssize_t count = 0;
        size_t total = 0;

        USBD_CDC_HandleTypeDef* pcd =
            (USBD_CDC_HandleTypeDef*) husbd_->pClassData;

        do
          {
            if (is_error_ == true)
              {
                is_error_ = false;
                errno = EIO;
                return -1;  // an error was reported, exit
              }

            // wait for possible previous ongoing write operation to finish
            while (pcd->TxState != 0)
              {
                // busy, wait
              }

            memcpy (tx_buff_, p + total,
                    count = std::min (tx_buff_size_, nbyte - total));

            // send the buffer, as much as we can
            USBD_CDC_SetTxBuffer (husbd_, tx_buff_, count);
            result = (USBD_StatusTypeDef) USBD_CDC_TransmitPacket (husbd_);

            if (result != USBD_OK)
              {
                count = -1;
                switch (result)
                  {
                  case USBD_BUSY:
                    errno = EBUSY;
                    break;

                  default:
                    errno = EIO;
                    break;
                  }
                break;
              }

            total += count;
          }
        while (total < nbyte);

        if (total > 0 && nbyte % packet_size_ == 0)
          {
            // send a zero length packet
            while (pcd->TxState != 0)
              {
                // busy, wait
              }
            USBD_CDC_SetTxBuffer (husbd_, tx_buff_, 0);
            USBD_CDC_TransmitPacket (husbd_);
          }

        return total;
      }

      bool
      uart_cdc_dev::do_is_opened (void)
      {
        return is_opened_;
      }

      bool
      uart_cdc_dev::do_is_connected (void)
      {
        return is_connected_;
      }

      int
      uart_cdc_dev::do_tcgetattr (struct termios *ptio)
      {
        // clear the termios structure
        bzero ((void *) ptio, sizeof(struct termios));

        // TODO: get the following parameters from the USB driver (CDC control)
        // termios.h: CSIZE: CS5, CS6, CS7, CS8; ST can CS7 and CS8 only
        ptio->c_cflag = CS8;

        // termios.h: CSTOPB: if true, two stop bits, otherwise only one
        ptio->c_cflag |= 0;

        // termios.h: flags PARENB = parity enabled, PARODD = parity odd
        ptio->c_cflag |= 0;

        // get baud rate
        ptio->c_ispeed = 115200L;
        ptio->c_ospeed = 115200L;

        // termios.h: CRTSCTS: no flow control
        ptio->c_cflag |= 0;

        // termios.h: retrieve supported control characters (c_cc[])
        // we use the "spare 2" character for a fine grained delay (1 ms)
        ptio->c_cc[VMIN] = cc_vmin_;
        ptio->c_cc[VTIME] = cc_vtime_;
        ptio->c_cc[VTIME_MS] = cc_vtime_milli_;

        return 0;
      }

      int
      uart_cdc_dev::do_tcsetattr (int options, const struct termios *ptio)
      {
        USBD_StatusTypeDef result = USBD_OK;

        // TODO: set c_cflag accordingly through the USB driver (CDC control)
        cc_vmin_ = ptio->c_cc[VMIN];
        cc_vtime_ = ptio->c_cc[VTIME];
        // we expect in the "spare 2" character the fine grained delay (1 ms)
        cc_vtime_milli_ =
            (ptio->c_cc[VTIME_MS] > 99) ? 99 : ptio->c_cc[VTIME_MS];

        // compute rx timeout
        if (o_nonblock_)
          {
            rx_timeout_ = 0;
          }
        else
          {
            if (cc_vtime_ == 0 && cc_vtime_milli_ == 0)
              {
                rx_timeout_ = 0xFFFFFFFF;
              }
            else
              {
                // VTIME is expressed in 0.1 seconds
                rx_timeout_ = cc_vtime_ * 100 + cc_vtime_milli_;
              }
          }

        // evaluate the options
        switch (options)
          {
          case TCSAFLUSH:
            // flush input
            do_tcflush (TCIFLUSH);
            // no break, falls through

          case TCSADRAIN:
            // wait for output to be drained
            if (husbd_ != nullptr)
              {
                USBD_CDC_HandleTypeDef* pcd =
                    (USBD_CDC_HandleTypeDef*) husbd_->pClassData;
                while (pcd->TxState != 0)
                  {
                    // busy, wait
                    rtos::sysclock.sleep_for (1);
                  }
              }
          }

        // TODO: send the new configuration

        if (result != USBD_OK)
          {
            switch (result)
              {
              case USBD_BUSY:
                errno = EBUSY;
                break;

              default:
                errno = EINVAL;
                break;
              }
            return -1;
          }

        return 0;
      }

      int
      uart_cdc_dev::do_tcflush (int queue_selector)
      {
        USBD_StatusTypeDef hal_result = USBD_OK;
        int result = 0;

        if (queue_selector > TCIOFLUSH)
          {
            errno = EINVAL;
            result = -1;
          }
        else
          {
            if (queue_selector & TCIFLUSH)
              {
                rx_sem_.reset ();
                rx_in_ = rx_out_ = 0;
              }

            if (queue_selector & TCOFLUSH)
              {
                ; // nothing to do
              }

            if (hal_result != USBD_OK)
              {
                errno = EIO;
                result = -1;
              }
          }
        return result;
      }

      int
      uart_cdc_dev::do_tcsendbreak (int duration)
      {
        return 0;
      }

// --------------------------------------------------------------------

// The following call-backs are executed on an interrupt context

      int8_t
      uart_cdc_dev::cb_init_event (void)
      {
        // get packet size; at this point the host/device negotiation is done
        packet_size_ = (husbd_->dev_speed == USBD_SPEED_HIGH) ? //
            USB_HS_MAX_PACKET_SIZE :
            USB_FS_MAX_PACKET_SIZE;
        is_connected_ = true;

        init_sem_.post ();

        return USBD_OK;
      }

      int8_t
      uart_cdc_dev::cb_deinit_event (void)
      {
        // USB disconnected
        is_error_ = true;
        is_connected_ = false;
        rx_sem_.post ();

        return USBD_OK;
      }

      int8_t
      uart_cdc_dev::cb_control_event (uint8_t cmd, uint8_t* pbuf, uint16_t len)
      {
        // TODO: implement control commands
        return USBD_OK;
      }

      /**
       * @brief  Receive event call-back.
       */
      int8_t
      uart_cdc_dev::cb_receive_event (uint8_t* pbuf, uint32_t* len)
      {
        size_t xfered = *len;

        while (xfered--)
          {
            rx_buff_[rx_in_++] = *pbuf++;
            if (rx_in_ >= rx_buff_size_)
              {
                rx_in_ = 0;
              }
          }

        // restart receive
        USBD_CDC_SetRxBuffer (husbd_, cdc_buff_);
        USBD_CDC_ReceivePacket (husbd_);

        // inform background we have something
        rx_sem_.post ();

        return USBD_OK;
      }
    } /* namespace stm32f7 */
  } /* namespace driver */
} /* namespace os */

#pragma GCC diagnostic pop

<commit_msg>At read(), don't exit until the last block from the USB peripheral is received.<commit_after>/*
 * uart-cdc-dev.cpp
 *
 * Copyright (c) 2018 Lix N. Paulian (lix@paulian.net)
 *
 * 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.
 *
 * Created on: 13 Jan 2018 (LNP)
 */

#include <cmsis-plus/rtos/os.h>
#include <cmsis-plus/diag/trace.h>

#include <uart-cdc-dev.h>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"

namespace os
{
  namespace driver
  {
    namespace stm32f7
    {

      uart_cdc_dev::uart_cdc_dev (const char* name, uint8_t usb_id,
                                  uint8_t* tx_buff, uint8_t* rx_buff,
                                  size_t tx_buff_size, size_t rx_buff_size) : //
          tty
            { name }, //
          usb_id_
            { usb_id }, //
          tx_buff_
            { tx_buff }, //
          rx_buff_
            { rx_buff }, //
          tx_buff_size_
            { tx_buff_size }, //
          rx_buff_size_
            { rx_buff_size }
      {
        trace::printf ("%s() %p\n", __func__, this);
      }

      uart_cdc_dev::~uart_cdc_dev ()
      {
        trace::printf ("%s() %p\n", __func__, this);

        is_opened_ = false;
      }

      int
      uart_cdc_dev::do_vopen (const char* path, int oflag, std::va_list args)
      {
        int result = -1;

        do
          {
            if (is_opened_)
              {
                errno = EEXIST; // already opened
                break;
              }

            // initialize FIFO
            rx_in_ = rx_out_ = 0;

            // reset semaphores
            init_sem_.reset ();
            rx_sem_.reset ();

            // initialize the USB peripheral
            if ((husbd_ = USB_DEVICE_Init (usb_id_)) == nullptr)
              {
                errno = EIO;
                break;
              }

            // if no rx/tx static buffers supplied, create them dynamically
            if (tx_buff_ == nullptr)
              {
                if ((tx_buff_ = new uint8_t[tx_buff_size_]) == nullptr)
                  {
                    errno = ENOMEM;
                    break;
                  }
                else
                  {
                    tx_buff_dyn_ = true;
                  }
              }
            else
              {
                tx_buff_dyn_ = false;
              }

            if (rx_buff_ == nullptr)
              {
                if ((rx_buff_ = new uint8_t[rx_buff_size_]) == nullptr)
                  {
                    if (tx_buff_dyn_ == true)
                      {
                        delete[] tx_buff_;
                        tx_buff_ = nullptr;
                      }
                    errno = ENOMEM;
                    break;
                  }
                else
                  {
                    rx_buff_dyn_ = true;
                  }
              }
            else
              {
                rx_buff_dyn_ = false;
              }

            // set initial timeout depending on the O_NONBLOCK flag
            if (oflag & O_NONBLOCK)
              {
                rx_timeout_ = 0x0;
                o_nonblock_ = true;
              }
            else
              {
                rx_timeout_ = 0xFFFFFFFF;
                o_nonblock_ = false;
              }

            // wait for the usb device initialization to complete
            init_sem_.wait ();

            if ((cdc_buff_ = new uint8_t[packet_size_]) == nullptr)
              {
                if (tx_buff_dyn_ == true)
                  {
                    delete[] tx_buff_;
                    tx_buff_ = nullptr;
                  }
                if (rx_buff_dyn_ == true)
                  {
                    delete[] rx_buff_;
                    rx_buff_ = nullptr;
                  }
                errno = ENOMEM;
                break;
              }

            is_opened_ = true;
            result = 0;

            // start receiving, basically wait for input characters
            USBD_CDC_SetRxBuffer (husbd_, cdc_buff_);
            USBD_CDC_ReceivePacket (husbd_);
          }
        while (false);

        return result;
      }

      int
      uart_cdc_dev::do_close (void)
      {
        // wait for potential ongoing write operation to finish
        if (husbd_ != nullptr)
          {
            USBD_CDC_HandleTypeDef* pcd =
                (USBD_CDC_HandleTypeDef*) husbd_->pClassData;
            int count = 100;      // 100 ms timeout
            while (pcd->TxState != 0 && count--)
              {
                // busy, wait
                rtos::sysclock.sleep_for (1);
              }
          }
        // shut down the USB peripheral
        USBD_DeInit (husbd_);

        // clean-up dynamic allocations, if any
        if (tx_buff_dyn_ == true)
          {
            delete[] tx_buff_;
            tx_buff_ = nullptr;
          }

        if (rx_buff_dyn_ == true)
          {
            delete[] rx_buff_;
            rx_buff_ = nullptr;
          }

        delete[] cdc_buff_;

        is_opened_ = false;

        return 0;
      }

      ssize_t
      uart_cdc_dev::do_read (void* buf, std::size_t nbyte)
      {
        uint8_t* lbuf = (uint8_t *) buf;
        ssize_t count = 0;

        os::rtos::clock::duration_t timeout =
            o_nonblock_ ? 0 : (cc_vmin_ > 0) ? 0xFFFFFFFF : rx_timeout_;

        uint32_t last_count = rx_in_;

        do
          {
            while (rx_out_ == rx_in_)
              {
                if (rx_sem_.timed_wait (timeout) != os::rtos::result::ok)
                  {
                    if (last_count == rx_in_)
                      {
                        // no more chars received: that means inter-char timeout
                        // return number of chars collected, if any
                        break;
                      }
                    last_count = rx_in_;
                  }
                if (is_error_ == true)
                  {
                    is_error_ = false;
                    errno = EIO;
                    return -1;  // an error was reported, exit
                  }
              }

            // retrieve accumulated chars, if any
            while (rx_out_ != rx_in_ && count < (ssize_t) nbyte)
              {
                *lbuf++ = rx_buff_[rx_out_++];
                if (++count == 1)
                  {
                    // VMIN > 0, apply timeout (can be infinitum too)
                    timeout = rx_timeout_;
                  }
                if (rx_out_ >= rx_buff_size_)
                  {
                    rx_out_ = 0;
                  }
              }
            if (count >= (ssize_t) nbyte)
              {
                break;
              }
          }
        while (last_packet_ == false || count < cc_vmin_);

        last_packet_ = false;

        return count;
      }

      ssize_t
      uart_cdc_dev::do_write (const void* buf, std::size_t nbyte)
      {
        USBD_StatusTypeDef result;
        uint8_t* p = (uint8_t*) buf;
        ssize_t count = 0;
        size_t total = 0;

        USBD_CDC_HandleTypeDef* pcd =
            (USBD_CDC_HandleTypeDef*) husbd_->pClassData;

        do
          {
            if (is_error_ == true)
              {
                is_error_ = false;
                errno = EIO;
                return -1;  // an error was reported, exit
              }

            // wait for possible previous ongoing write operation to finish
            while (pcd->TxState != 0)
              {
                // busy, wait
              }

            memcpy (tx_buff_, p + total,
                    count = std::min (tx_buff_size_, nbyte - total));

            // send the buffer, as much as we can
            USBD_CDC_SetTxBuffer (husbd_, tx_buff_, count);
            result = (USBD_StatusTypeDef) USBD_CDC_TransmitPacket (husbd_);

            if (result != USBD_OK)
              {
                count = -1;
                switch (result)
                  {
                  case USBD_BUSY:
                    errno = EBUSY;
                    break;

                  default:
                    errno = EIO;
                    break;
                  }
                break;
              }

            total += count;
          }
        while (total < nbyte);

        if (total > 0 && nbyte % packet_size_ == 0)
          {
            // send a zero length packet
            while (pcd->TxState != 0)
              {
                // busy, wait
              }
            USBD_CDC_SetTxBuffer (husbd_, tx_buff_, 0);
            USBD_CDC_TransmitPacket (husbd_);
          }

        return total;
      }

      bool
      uart_cdc_dev::do_is_opened (void)
      {
        return is_opened_;
      }

      bool
      uart_cdc_dev::do_is_connected (void)
      {
        return is_connected_;
      }

      int
      uart_cdc_dev::do_tcgetattr (struct termios *ptio)
      {
        // clear the termios structure
        bzero ((void *) ptio, sizeof(struct termios));

        // TODO: get the following parameters from the USB driver (CDC control)
        // termios.h: CSIZE: CS5, CS6, CS7, CS8; ST can CS7 and CS8 only
        ptio->c_cflag = CS8;

        // termios.h: CSTOPB: if true, two stop bits, otherwise only one
        ptio->c_cflag |= 0;

        // termios.h: flags PARENB = parity enabled, PARODD = parity odd
        ptio->c_cflag |= 0;

        // get baud rate
        ptio->c_ispeed = 115200L;
        ptio->c_ospeed = 115200L;

        // termios.h: CRTSCTS: no flow control
        ptio->c_cflag |= 0;

        // termios.h: retrieve supported control characters (c_cc[])
        // we use the "spare 2" character for a fine grained delay (1 ms)
        ptio->c_cc[VMIN] = cc_vmin_;
        ptio->c_cc[VTIME] = cc_vtime_;
        ptio->c_cc[VTIME_MS] = cc_vtime_milli_;

        return 0;
      }

      int
      uart_cdc_dev::do_tcsetattr (int options, const struct termios *ptio)
      {
        USBD_StatusTypeDef result = USBD_OK;

        // TODO: set c_cflag accordingly through the USB driver (CDC control)
        cc_vmin_ = ptio->c_cc[VMIN];
        cc_vtime_ = ptio->c_cc[VTIME];
        // we expect in the "spare 2" character the fine grained delay (1 ms)
        cc_vtime_milli_ =
            (ptio->c_cc[VTIME_MS] > 99) ? 99 : ptio->c_cc[VTIME_MS];

        // compute rx timeout
        if (o_nonblock_)
          {
            rx_timeout_ = 0;
          }
        else
          {
            if (cc_vtime_ == 0 && cc_vtime_milli_ == 0)
              {
                rx_timeout_ = 0xFFFFFFFF;
              }
            else
              {
                // VTIME is expressed in 0.1 seconds
                rx_timeout_ = cc_vtime_ * 100 + cc_vtime_milli_;
              }
          }

        // evaluate the options
        switch (options)
          {
          case TCSAFLUSH:
            // flush input
            do_tcflush (TCIFLUSH);
            // no break, falls through

          case TCSADRAIN:
            // wait for output to be drained
            if (husbd_ != nullptr)
              {
                USBD_CDC_HandleTypeDef* pcd =
                    (USBD_CDC_HandleTypeDef*) husbd_->pClassData;
                while (pcd->TxState != 0)
                  {
                    // busy, wait
                    rtos::sysclock.sleep_for (1);
                  }
              }
          }

        // TODO: send the new configuration

        if (result != USBD_OK)
          {
            switch (result)
              {
              case USBD_BUSY:
                errno = EBUSY;
                break;

              default:
                errno = EINVAL;
                break;
              }
            return -1;
          }

        return 0;
      }

      int
      uart_cdc_dev::do_tcflush (int queue_selector)
      {
        USBD_StatusTypeDef hal_result = USBD_OK;
        int result = 0;

        if (queue_selector > TCIOFLUSH)
          {
            errno = EINVAL;
            result = -1;
          }
        else
          {
            if (queue_selector & TCIFLUSH)
              {
                rx_sem_.reset ();
                rx_in_ = rx_out_ = 0;
                last_packet_ = false;
              }

            if (queue_selector & TCOFLUSH)
              {
                ; // nothing to do
              }

            if (hal_result != USBD_OK)
              {
                errno = EIO;
                result = -1;
              }
          }
        return result;
      }

      int
      uart_cdc_dev::do_tcsendbreak (int duration)
      {
        return 0;
      }

// --------------------------------------------------------------------

// The following call-backs are executed on an interrupt context

      int8_t
      uart_cdc_dev::cb_init_event (void)
      {
        // get packet size; at this point the host/device negotiation is done
        packet_size_ = (husbd_->dev_speed == USBD_SPEED_HIGH) ? //
            USB_HS_MAX_PACKET_SIZE :
            USB_FS_MAX_PACKET_SIZE;
        is_connected_ = true;

        init_sem_.post ();

        return USBD_OK;
      }

      int8_t
      uart_cdc_dev::cb_deinit_event (void)
      {
        // USB disconnected
        is_error_ = true;
        is_connected_ = false;
        rx_sem_.post ();

        return USBD_OK;
      }

      int8_t
      uart_cdc_dev::cb_control_event (uint8_t cmd, uint8_t* pbuf, uint16_t len)
      {
        // TODO: implement control commands
        return USBD_OK;
      }

      /**
       * @brief  Receive event call-back.
       */
      int8_t
      uart_cdc_dev::cb_receive_event (uint8_t* pbuf, uint32_t* len)
      {
        size_t xfered = *len;

        while (xfered--)
          {
            rx_buff_[rx_in_++] = *pbuf++;
            if (rx_in_ >= rx_buff_size_)
              {
                rx_in_ = 0;
              }
          }

        // restart receive
        USBD_CDC_SetRxBuffer (husbd_, cdc_buff_);
        USBD_CDC_ReceivePacket (husbd_);

        // last packet?
        xfered = *len;
        if (xfered == 0 || xfered % packet_size_ > 0)
          {
            last_packet_ = true; // yes
          }

        // inform background we have something
        rx_sem_.post ();

        return USBD_OK;
      }
    } /* namespace stm32f7 */
  } /* namespace driver */
} /* namespace os */

#pragma GCC diagnostic pop

<|endoftext|>


<commit_before>#include <regex>
#include <map>
#include <algorithm>

#include <sys/stat.h>
#include <fstream>

#include "tcp.hpp"

namespace net11 {
	class http_connection;
	class http_response;
	class http_websocket;

	http_response* make_text_response(int code,std::map<std::string,std::string> &head,std::string &data);

	class http_response {
		friend http_connection;
		friend http_response* make_stream_response(int code,std::map<std::string,std::string> &head,std::function<bool(buffer &data)> prod);

		int code;
		std::map<std::string,std::string> head;
		std::function<bool(buffer &)> prod;

		http_response(){}
	protected:
		virtual bool produce(http_connection &conn);
	public:
		void set_header(std::string &k,std::string &v) {
			for (int i=0;i<k.size();i++) {
				if (isupper(k[i])) {
					std::string k2;
					for (i=0;i<k.size();i++)
						k2.push_back(tolower(k[i]));
					head[k2]=v;
					return;
				}
			}
			head[k]=v;
		}
		virtual ~http_response() {}
	};

	class http_connection : public net11::connection {
		friend std::function<net11::connection*()> make_http_server(std::function<http_response*(http_connection &conn)> route);
		friend http_response;
		std::shared_ptr<sink> reqlinesink;
		std::shared_ptr<std::regex> rereqline;
		std::string reqline[3];

		std::shared_ptr<sink> headsink;
		std::map<std::string,std::string> headers;

		std::function<http_response*(http_connection &conn)> router;

		http_connection(
			std::shared_ptr<std::regex> in_re,
			std::function<http_response*(http_connection &conn)> in_router
		):rereqline(in_re),router(in_router) {
			reqlinesink=std::shared_ptr<sink>(new net11::line_parser_sink("\r\n",4096,[this](std::string &l){
				std::smatch sma;
				//std::cout<<"REqline:"<<l<<"\n";
				if (std::regex_match(l,sma,*rereqline)) {
					reqline[0]=sma.str(1);
					reqline[1]=sma.str(2);
					if (sma.size()<3) {
						reqline[2]="";
					} else {
						reqline[2]=sma.str(3);
					}
					this->current_sink=headsink;
					return true;
				} else {
					// TODO: error handling?!
					return false;
				}
			}));
			headsink=std::shared_ptr<sink>(new header_parser_sink(128*1024,
				[this](std::string &k,std::string &v){
					//std::cout<<"HeadKey=["<<k<<"] HeadValue=["<<v<<"]\n";
					headers[k]=v;
					return true;
				},
				[this](const char *err) {
					//std::cout<<"req:"<<reqline[0]<<" url:"<<reqline[1]<<" ver:"<<reqline[2]<<"\n";

					// TODO: urlencodings?
					http_response *r=router(*this);
					if (!r) {
						std::map<std::string,std::string> head; //{{"connection","close"}};
						r=make_text_response(404,head,"Error 404, "+url()+" not found");
					}
					// reset our sink in case the response wants to hijack it
					this->current_sink=reqlinesink;
					// TODO: make sure that connection lines are there?
					bool rv=r->produce(*this);
					delete r;
					reqline[0].resize(0);
					reqline[1].resize(0);
					reqline[2].resize(0);
					headers.clear();
					return rv;
				}
			));
			current_sink=reqlinesink;
		}
		virtual ~http_connection() {
			//printf("destroying http_connection\n");
		}
	public:
		std::string& method() {
			return reqline[0];
		}
		std::string& url() {
			return reqline[1]; // TODO should it be pre-decoded?
		}
		std::string* header(std::string &k) {
			auto f=headers.find(k);
			if (f!=headers.end())
				return &f->second;
			else
				return 0;
		}
	};

	std::function<net11::connection*()> make_http_server(std::function<http_response*(http_connection &conn)> route) {
		// init the regexp once if the regex compiler is slow.
		std::shared_ptr<std::regex> re(new std::regex("(\\S+)\\s+(\\S+)(?:\\s+(.+))?"));

		// now create a connection spawn function
		return [re,route]() {
			return (net11::connection*)new http_connection(re,route);
		};
	};

	http_response* make_stream_response(int code,std::map<std::string,std::string> &head,std::function<bool(buffer &data)> prod) {
		auto out=new http_response();
		out->code=code;
		out->head=head;
		out->prod=prod;
		return out;
	}

	http_response* make_blob_response(int code,std::map<std::string,std::string> &head,std::vector<char> &in_data) {
		auto rv=make_stream_response(code,head,make_data_producer(in_data));
		rv->set_header(std::string("content-length"),std::to_string(in_data.size()));
		return rv;
	}
	http_response* make_blob_response(int code,std::map<std::string,std::string> head,std::vector<char> &in_data) {
		auto rv=make_stream_response(code,head,make_data_producer(in_data));
		rv->set_header(std::string("content-length"),std::to_string(in_data.size()));
		return rv;
	}
	http_response* make_text_response(int code,std::map<std::string,std::string> &head,std::string &in_data) {
		auto rv=make_stream_response(code,head,make_data_producer(in_data));
		rv->set_header(std::string("content-length"),std::to_string(in_data.size()));
		return rv;
	}
	http_response* make_text_response(int code,std::map<std::string,std::string> head,std::string in_data) {
		auto rv=make_stream_response(code,head,make_data_producer(in_data));
		rv->set_header(std::string("content-length"),std::to_string(in_data.size()));
		return rv;
	}

	bool http_response::produce(http_connection &conn) {
		std::string resline="HTTP/1.1 "+std::to_string(code)+" some message\r\n";
		for(auto kv:head) {
			resline=resline+kv.first+": "+kv.second+"\r\n";
		}
		resline+="\r\n";
		conn.producers.push_back(make_data_producer(resline));
		if (head.count("content-length")) {
			conn.producers.push_back(prod);
		} else {
			abort(); //conn.producers.push_back([this](
		}
		return true;
	}

	http_response* make_file_response(std::string base,std::string checked) {
		struct stat stbuf;
		int last='/';
		int end=checked.size();
		for (int i=0;i<checked.size();i++) {
			if (checked[i]=='\\')
				return make_text_response(500,{},"Bad request, \\ not allowed in url");
			if (checked[i]=='?') {
				end=i;
				break;
			}
			if (last=='/') {
				if (checked[i]=='.') {
					return make_text_response(500,{},"Bad request with a dotfile named file comming after a /");
				} else if (checked[i]=='/') {
					return make_text_response(500,{},"Bad request, multiple // after eachother");
				}
			}
			if (checked[i]=='/') {
				// check for directory presence!
				std::string tmp=base+checked.substr(0,i);
				int sr=stat( tmp.c_str(),&stbuf);
				if (sr) {
					return make_text_response(404,{},"Not found "+checked.substr(0,i));
				}
				if (!(stbuf.st_mode&S_IFDIR)) {
					return make_text_response(404,{},"Not a dir "+checked.substr(0,i));
				}
			}
			last=checked[i];
		}
		std::string tmp=base+checked.substr(0,end);
		if (stat(tmp.c_str(),&stbuf)) {
			return make_text_response(404,{},"Not found "+checked.substr(0,end));
		}
		if (!(stbuf.st_mode&S_IFREG)) {
			return make_text_response(404,{},"Not a file "+checked.substr(0,end));
		}

		FILE *f=fopen(tmp.c_str(),"rb");
		if (!f)
			return make_text_response(400,{},"Could not open file "+checked.substr(0,end));
		struct fh {
			FILE *f;
			fh(FILE *in_f):f(in_f){}
			~fh() {
				fclose(f);
			}
		};
		std::shared_ptr<fh> fp(new fh(f));

		std::map<std::string,std::string> head={
			{"content-length",std::to_string(stbuf.st_size)}
		};
		return make_stream_response(200,head,[fp](buffer &ob) {
			int osz=ob.usage();
			int tr=ob.compact();
			int rc=fread(ob.to_produce(),1,tr,fp->f);
			if (rc>=0) {
				ob.produced(osz+rc);
			}
			if (rc<=0) {
				if (feof(fp->f))
					return false;
			}
			return true;
		});
	}
}

<commit_msg>* some g++ and clang++ compilation fixes<commit_after>#include <string>
#include <regex>
#include <map>
#include <algorithm>

#include <sys/stat.h>
#include <fstream>

#include "tcp.hpp"

namespace net11 {
	class http_connection;
	class http_response;
	class http_websocket;

	http_response* make_text_response(int code,std::map<std::string,std::string> &head,std::string &data);

	class http_response {
		friend http_connection;
		friend http_response* make_stream_response(int code,const std::map<std::string,std::string> &head,std::function<bool(buffer &data)> prod);

		int code;
		std::map<std::string,std::string> head;
		std::function<bool(buffer &)> prod;

		http_response(){}
	protected:
		virtual bool produce(http_connection &conn);
	public:
		void set_header(const std::string &k,const std::string &v) {
			for (int i=0;i<k.size();i++) {
				if (isupper(k[i])) {
					std::string k2;
					for (i=0;i<k.size();i++)
						k2.push_back(tolower(k[i]));
					head[k2]=v;
					return;
				}
			}
			head[k]=v;
		}
		virtual ~http_response() {}
	};

	class http_connection : public net11::connection {
		friend std::function<net11::connection*()> make_http_server(std::function<http_response*(http_connection &conn)> route);
		friend http_response;
		std::shared_ptr<sink> reqlinesink;
		std::shared_ptr<std::regex> rereqline;
		std::string reqline[3];

		std::shared_ptr<sink> headsink;
		std::map<std::string,std::string> headers;

		std::function<http_response*(http_connection &conn)> router;

		http_connection(
			std::shared_ptr<std::regex> in_re,
			std::function<http_response*(http_connection &conn)> in_router
		):rereqline(in_re),router(in_router) {
			reqlinesink=std::shared_ptr<sink>(new net11::line_parser_sink("\r\n",4096,[this](std::string &l){
				std::smatch sma;
				//std::cout<<"REqline:"<<l<<"\n";
				if (std::regex_match(l,sma,*rereqline)) {
					reqline[0]=sma.str(1);
					reqline[1]=sma.str(2);
					if (sma.size()<3) {
						reqline[2]="";
					} else {
						reqline[2]=sma.str(3);
					}
					this->current_sink=headsink;
					return true;
				} else {
					// TODO: error handling?!
					return false;
				}
			}));
			headsink=std::shared_ptr<sink>(new header_parser_sink(128*1024,
				[this](std::string &k,std::string &v){
					//std::cout<<"HeadKey=["<<k<<"] HeadValue=["<<v<<"]\n";
					headers[k]=v;
					return true;
				},
				[this](const char *err) {
					//std::cout<<"req:"<<reqline[0]<<" url:"<<reqline[1]<<" ver:"<<reqline[2]<<"\n";

					// TODO: urlencodings?
					http_response *r=router(*this);
					if (!r) {
						std::map<std::string,std::string> head; //{{"connection","close"}};
						std::string msg="Error 404, "+url()+" not found";
						r=make_text_response(404,head,msg);
					}
					// reset our sink in case the response wants to hijack it
					this->current_sink=reqlinesink;
					// TODO: make sure that connection lines are there?
					bool rv=r->produce(*this);
					delete r;
					reqline[0].resize(0);
					reqline[1].resize(0);
					reqline[2].resize(0);
					headers.clear();
					return rv;
				}
			));
			current_sink=reqlinesink;
		}
		virtual ~http_connection() {
			//printf("destroying http_connection\n");
		}
	public:
		std::string& method() {
			return reqline[0];
		}
		std::string& url() {
			return reqline[1]; // TODO should it be pre-decoded?
		}
		std::string* header(std::string &k) {
			auto f=headers.find(k);
			if (f!=headers.end())
				return &f->second;
			else
				return 0;
		}
	};

	std::function<net11::connection*()> make_http_server(std::function<http_response*(http_connection &conn)> route) {
		// init the regexp once if the regex compiler is slow.
		std::shared_ptr<std::regex> re(new std::regex("(\\S+)\\s+(\\S+)(?:\\s+(.+))?"));

		// now create a connection spawn function
		return [re,route]() {
			return (net11::connection*)new http_connection(re,route);
		};
	};

	http_response* make_stream_response(int code,const std::map<std::string,std::string> &head,std::function<bool(buffer &data)> prod) {
		auto out=new http_response();
		out->code=code;
		out->head=head;
		out->prod=prod;
		return out;
	}

	http_response* make_blob_response(int code,const std::map<std::string,std::string> &head,std::vector<char> &in_data) {
		auto rv=make_stream_response(code,head,make_data_producer(in_data));
		rv->set_header(std::string("content-length"),std::to_string(in_data.size()));
		return rv;
	}
	http_response* make_blob_response(int code,const std::map<std::string,std::string> head,std::vector<char> &in_data) {
		auto rv=make_stream_response(code,head,make_data_producer(in_data));
		rv->set_header(std::string("content-length"),std::to_string(in_data.size()));
		return rv;
	}
	http_response* make_text_response(int code,const std::map<std::string,std::string> &head,std::string &in_data) {
		auto rv=make_stream_response(code,head,make_data_producer(in_data));
		rv->set_header(std::string("content-length"),std::to_string(in_data.size()));
		return rv;
	}
	http_response* make_text_response(int code,const std::map<std::string,std::string> head,std::string in_data) {
		auto rv=make_stream_response(code,head,make_data_producer(in_data));
		rv->set_header(std::string("content-length"),std::to_string(in_data.size()));
		return rv;
	}
	http_response* make_text_response(int code,const std::initializer_list<std::pair<const std::string,std::string>> &headinit,const std::string in_data) {
		auto rv=make_stream_response(code,std::map<std::string,std::string>(headinit),make_data_producer(in_data));
		rv->set_header(std::string("content-length"),std::to_string(in_data.size()));
		return rv;
	}

	bool http_response::produce(http_connection &conn) {
		std::string resline="HTTP/1.1 "+std::to_string(code)+" some message\r\n";
		for(auto kv:head) {
			resline=resline+kv.first+": "+kv.second+"\r\n";
		}
		resline+="\r\n";
		conn.producers.push_back(make_data_producer(resline));
		if (head.count("content-length")) {
			conn.producers.push_back(prod);
		} else {
			abort(); //conn.producers.push_back([this](
		}
		return true;
	}

	http_response* make_file_response(std::string base,std::string checked) {
		struct stat stbuf;
		int last='/';
		int end=checked.size();
		std::map<std::string,std::string> empty;
		for (int i=0;i<checked.size();i++) {
			if (checked[i]=='\\')
				return make_text_response(500,empty,"Bad request, \\ not allowed in url");
			if (checked[i]=='?') {
				end=i;
				break;
			}
			if (last=='/') {
				if (checked[i]=='.') {
					return make_text_response(500,empty,"Bad request with a dotfile named file comming after a /");
				} else if (checked[i]=='/') {
					return make_text_response(500,empty,"Bad request, multiple // after eachother");
				}
			}
			if (checked[i]=='/') {
				// check for directory presence!
				std::string tmp=base+checked.substr(0,i);
				int sr=stat( tmp.c_str(),&stbuf);
				if (sr) {
					return make_text_response(404,empty,"Not found "+checked.substr(0,i));
				}
				if (!(stbuf.st_mode&S_IFDIR)) {
					return make_text_response(404,empty,"Not a dir "+checked.substr(0,i));
				}
			}
			last=checked[i];
		}
		std::string tmp=base+checked.substr(0,end);
		if (stat(tmp.c_str(),&stbuf)) {
			return make_text_response(404,empty,"Not found "+checked.substr(0,end));
		}
		if (!(stbuf.st_mode&S_IFREG)) {
			return make_text_response(404,empty,"Not a file "+checked.substr(0,end));
		}

		FILE *f=fopen(tmp.c_str(),"rb");
		if (!f)
			return make_text_response(400,empty,"Could not open file "+checked.substr(0,end));
		struct fh {
			FILE *f;
			fh(FILE *in_f):f(in_f){}
			~fh() {
				fclose(f);
			}
		};
		std::shared_ptr<fh> fp(new fh(f));

		std::map<std::string,std::string> head={
			{"content-length",std::to_string(stbuf.st_size)}
		};
		return make_stream_response(200,head,[fp](buffer &ob) {
			int osz=ob.usage();
			int tr=ob.compact();
			int rc=fread(ob.to_produce(),1,tr,fp->f);
			if (rc>=0) {
				ob.produced(osz+rc);
			}
			if (rc<=0) {
				if (feof(fp->f))
					return false;
			}
			return true;
		});
	}
}

<|endoftext|>


<commit_before>/*
 *          Copyright Andrey Semashev 2007 - 2014.
 * Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 */
/*!
 * \file   unhandled_exception_count.cpp
 * \author Andrey Semashev
 * \date   05.11.2012
 *
 * \brief  This header is the Boost.Log library implementation, see the library documentation
 *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
 *
 * The code in this file is based on the implementation by Evgeny Panasyuk:
 *
 * https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp
 */

#include <exception>
#include <boost/log/detail/unhandled_exception_count.hpp>
#include <boost/log/detail/header.hpp>

namespace boost {

BOOST_LOG_OPEN_NAMESPACE

namespace aux {

BOOST_LOG_ANONYMOUS_NAMESPACE {

#if defined(BOOST_LOG_HAS_CXXABI_H)
// MinGW GCC 4.4 seem to not work the same way the newer GCC versions do. As a result, __cxa_get_globals based implementation will always return 0.
// Just disable it for now and fall back to std::uncaught_exception().
#if !defined(__MINGW32__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)))
// Only GCC 4.7 declares __cxa_get_globals() in cxxabi.h, older compilers do not expose this function but it's there
#define BOOST_LOG_HAS_CXA_GET_GLOBALS
extern "C" void* __cxa_get_globals();
#endif
#elif defined(_MSC_VER) && _MSC_VER >= 1400
#define BOOST_LOG_HAS_GETPTD
extern "C" void* _getptd();
#endif

} // namespace

//! Returns the number of currently pending exceptions
BOOST_LOG_API unsigned int unhandled_exception_count() BOOST_NOEXCEPT
{
#if defined(BOOST_LOG_HAS_CXA_GET_GLOBALS)
    // Tested on {clang 3.2,GCC 3.5.6,GCC 4.1.2,GCC 4.4.6,GCC 4.4.7}x{x32,x64}
    return *(reinterpret_cast< const unsigned int* >(static_cast< const char* >(__cxa_get_globals()) + sizeof(void*))); // __cxa_eh_globals::uncaughtExceptions, x32 offset - 0x4, x64 - 0x8
#elif defined(BOOST_LOG_HAS_GETPTD)
    // MSVC specific. Tested on {MSVC2005SP1,MSVC2008SP1,MSVC2010SP1,MSVC2012}x{x32,x64}.
    return *(reinterpret_cast< const unsigned int* >(static_cast< const char* >(_getptd()) + (sizeof(void*) == 8 ? 0x100 : 0x90))); // _tiddata::_ProcessingThrow, x32 offset - 0x90, x64 - 0x100
#else
    // Portable implementation. Does not allow to detect multiple nested exceptions.
    return static_cast< unsigned int >(std::uncaught_exception());
#endif
}

} // namespace aux

BOOST_LOG_CLOSE_NAMESPACE // namespace log

} // namespace boost

#include <boost/log/detail/footer.hpp>
<commit_msg>Fixed unhandled_exception_count() with gcc and clang.<commit_after>/*
 *          Copyright Andrey Semashev 2007 - 2014.
 * Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 */
/*!
 * \file   unhandled_exception_count.cpp
 * \author Andrey Semashev
 * \date   05.11.2012
 *
 * \brief  This header is the Boost.Log library implementation, see the library documentation
 *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
 *
 * The code in this file is based on the implementation by Evgeny Panasyuk:
 *
 * https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp
 */

#include <exception>
#include <boost/log/detail/unhandled_exception_count.hpp>
#include <boost/log/detail/header.hpp>

namespace boost {

BOOST_LOG_OPEN_NAMESPACE

namespace aux {

BOOST_LOG_ANONYMOUS_NAMESPACE {

// cxxabi.h availability macro
#if defined(BOOST_CLANG)
#   if defined(__has_include) && __has_include(<cxxabi.h>)
#       define BOOST_LOG_HAS_CXXABI_H
#   endif
#elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
#   define BOOST_LOG_HAS_CXXABI_H
#endif

#if defined(BOOST_LOG_HAS_CXXABI_H)
// MinGW GCC 4.4 seem to not work the same way the newer GCC versions do. As a result, __cxa_get_globals based implementation will always return 0.
// Just disable it for now and fall back to std::uncaught_exception().
#if !defined(__MINGW32__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)))
// Only GCC 4.7 declares __cxa_get_globals() in cxxabi.h, older compilers do not expose this function but it's there
#define BOOST_LOG_HAS_CXA_GET_GLOBALS
extern "C" void* __cxa_get_globals();
#endif
#elif defined(_MSC_VER) && _MSC_VER >= 1400
#define BOOST_LOG_HAS_GETPTD
extern "C" void* _getptd();
#endif

} // namespace

//! Returns the number of currently pending exceptions
BOOST_LOG_API unsigned int unhandled_exception_count() BOOST_NOEXCEPT
{
#if defined(BOOST_LOG_HAS_CXA_GET_GLOBALS)
    // Tested on {clang 3.2,GCC 3.5.6,GCC 4.1.2,GCC 4.4.6,GCC 4.4.7}x{x32,x64}
    return *(reinterpret_cast< const unsigned int* >(static_cast< const char* >(__cxa_get_globals()) + sizeof(void*))); // __cxa_eh_globals::uncaughtExceptions, x32 offset - 0x4, x64 - 0x8
#elif defined(BOOST_LOG_HAS_GETPTD)
    // MSVC specific. Tested on {MSVC2005SP1,MSVC2008SP1,MSVC2010SP1,MSVC2012}x{x32,x64}.
    return *(reinterpret_cast< const unsigned int* >(static_cast< const char* >(_getptd()) + (sizeof(void*) == 8 ? 0x100 : 0x90))); // _tiddata::_ProcessingThrow, x32 offset - 0x90, x64 - 0x100
#else
    // Portable implementation. Does not allow to detect multiple nested exceptions.
    return static_cast< unsigned int >(std::uncaught_exception());
#endif
}

} // namespace aux

BOOST_LOG_CLOSE_NAMESPACE // namespace log

} // namespace boost

#include <boost/log/detail/footer.hpp>
<|endoftext|>


<commit_before>/** \file
 *
 * Unit tests for the PhaseDuplicator, which replaces complex subgraphs with
 * observed traversals.
 */

#include <iostream>
#include "../phase_duplicator.hpp"
#include "../json2pb.h"

#include "catch.hpp"

namespace vg {
namespace unittest {

// Build a toy graph
const string duplicator_graph_1 = R"(
    {
        "node": [
            {"id": 1, "sequence": "G"},
            {"id": 2, "sequence": "A"},
            {"id": 3, "sequence": "T"},
            {"id": 4, "sequence": "GGG"},
            {"id": 5, "sequence": "T"},
            {"id": 6, "sequence": "A"},
            {"id": 7, "sequence": "C"},
            {"id": 8, "sequence": "A"},
            {"id": 9, "sequence": "A"}
        ],
        "edge": [
            {"from": 1, "to": 2},
            {"from": 1, "to": 6},
            {"from": 2, "to": 3},
            {"from": 2, "to": 4},
            {"from": 3, "to": 5},
            {"from": 4, "to": 5},
            {"from": 5, "to": 6},
            {"from": 6, "to": 7},
            {"from": 6, "to": 8},
            {"from": 7, "to": 9},
            {"from": 8, "to": 9}

        ],
        "path": [
            {"name": "hint", "mapping": [
<<<<<<< HEAD
                {"position": {"node_id": 1}, "rank": 1},
                {"position": {"node_id": 6}, "rank": 2},
                {"position": {"node_id": 8}, "rank": 3},
                {"position": {"node_id": 9}, "rank": 4}
=======
                {"position": {"node_id": 1}, "rank" : 1 },
                {"position": {"node_id": 6}, "rank" : 2 },
                {"position": {"node_id": 8}, "rank" : 3 },
                {"position": {"node_id": 9}, "rank" : 4 }
>>>>>>> upstream/master
            ]}
        ]
    }
    )";

TEST_CASE("PhaseDuplicator can emit a single traversal", "[phaseduplicator][indexing]") {

    // Make an actual graph
    Graph graph;
    json2pb(graph, duplicator_graph_1.c_str(), duplicator_graph_1.size());

    // Make an XG index of the graph
    xg::XG index(graph);

    // Add in a thread
    vector<xg::XG::thread_t> threads {{
        {1, false},
        {2, false},
        {3, false},
        {5, false},
        {6, false},
        {7, false},
        {9, false}
    }};
    index.insert_threads_into_dag(threads, {});

    // Make a duplicator
    PhaseDuplicator duplicator(index);

    // Define a subgraph to duplicate out
    set<id_t> to_duplicate {2, 3, 4, 5};
    // And the next ID to use
    id_t next_id = 10;

    // Do the duplication
    pair<Graph, vector<Translation>> result(duplicator.duplicate(to_duplicate, next_id));
    Graph& duped = result.first;
    vector<Translation>& translations = result.second;

#ifdef debug
    cerr << pb2json(duped) << endl;
#endif

    // Check the result
    SECTION("the duplicated graph should have 3 nodes") {
        REQUIRE(duped.node_size() == 3);

        SECTION("the nodes should be A, T, and T") {
            bool a_found = false;
            for (size_t i = 0; i < duped.node_size(); i++) {
                auto& node = duped.node(i);
                if (node.sequence() == "A") {
                    REQUIRE(!a_found);
                    a_found = true;
                } else {
                    REQUIRE(node.sequence() == "T");
                }
            }
            REQUIRE(a_found);
        }
    }

    SECTION("the duplicated graph should have 4 edges") {
        REQUIRE(duped.edge_size() == 4);
    }

    SECTION("there should be 1 translation") {
        REQUIRE(translations.size() == 1);

        auto& translation = translations.front();

        SECTION("the translation should have 3 mappings in each path") {
            REQUIRE(translation.from().mapping_size() == 3);
            REQUIRE(translation.to().mapping_size() == 3);

            SECTION("the from mappings should trace the original path") {
                REQUIRE(translation.from().mapping(0).position().node_id() == 2);
                REQUIRE(translation.from().mapping(0).position().is_reverse() == false);
                REQUIRE(translation.from().mapping(1).position().node_id() == 3);
                REQUIRE(translation.from().mapping(1).position().is_reverse() == false);
                REQUIRE(translation.from().mapping(2).position().node_id() == 5);
                REQUIRE(translation.from().mapping(2).position().is_reverse() == false);
            }

            SECTION("the to mappings should also spell out ATT") {
                // We need to index the duplicated nodes
                map<id_t, Node> id_to_node;
                for (size_t i = 0; i < duped.node_size(); i++) {
                    id_to_node[duped.node(i).id()] = duped.node(i);
                }

                for (size_t i = 0; i < translation.to().mapping_size(); i++) {
                    // All the mappings have to be to forward copies of these nodes.
                    auto& mapping = translation.to().mapping(i);
                    REQUIRE(id_to_node.count(mapping.position().node_id()));
                    REQUIRE(mapping.position().is_reverse() == false);
                }

                // And when we look at the nodes they need the right sequences
                REQUIRE(id_to_node[translation.to().mapping(0).position().node_id()].sequence() == "A");
                REQUIRE(id_to_node[translation.to().mapping(1).position().node_id()].sequence() == "T");
                REQUIRE(id_to_node[translation.to().mapping(2).position().node_id()].sequence() == "T");
            }
        }

    }

}

TEST_CASE("PhaseDuplicator can deduplicate identical traversals", "[phaseduplicator][indexing]") {

    // Make a graph

    // Make an actual graph
    Graph graph;
    json2pb(graph, duplicator_graph_1.c_str(), duplicator_graph_1.size());

    // Make an XG index of the graph
    xg::XG index(graph);

    // Add in a thread
    vector<xg::XG::thread_t> threads {{
        {1, false},
        {2, false},
        {3, false},
        {5, false},
        {6, false},
        {7, false},
        {9, false}
    }, {
        {1, false},
        {2, false},
        {3, false},
        {5, false},
        {6, false},
        {7, false},
        {9, false}
    }, {
        {9, true},
        {7, true},
        {6, true},
        {5, true},
        {3, true},
        {2, true},
        {1, true}
    }};
    index.insert_threads_into_dag(threads, {});

    // Make a duplicator
    PhaseDuplicator duplicator(index);

    // Define a subgraph to duplicate out
    set<id_t> to_duplicate {2, 3, 4, 5};
    // And the next ID to use
    id_t next_id = 10;

    // Do the duplication
    pair<Graph, vector<Translation>> result(duplicator.duplicate(to_duplicate, next_id));
    Graph& duped = result.first;
    vector<Translation>& translations = result.second;

#ifdef debug
    cerr << pb2json(duped) << endl;
#endif

    // Check the result
    SECTION("the duplicated graph should have 3 nodes") {
        REQUIRE(duped.node_size() == 3);

        SECTION("the nodes should be A, T, and T") {
            bool a_found = false;
            for (size_t i = 0; i < duped.node_size(); i++) {
                auto& node = duped.node(i);
                if (node.sequence() == "A") {
                    REQUIRE(!a_found);
                    a_found = true;
                } else {
                    REQUIRE(node.sequence() == "T");
                }
            }
            REQUIRE(a_found);
        }
    }

    SECTION("the duplicated graph should have 4 edges") {
        REQUIRE(duped.edge_size() == 4);
    }
}

TEST_CASE("PhaseDuplicator can produce internal traversals", "[phaseduplicator][indexing]") {

    // Make a graph

    // Make an actual graph
    Graph graph;
    json2pb(graph, duplicator_graph_1.c_str(), duplicator_graph_1.size());

    // Make an XG index of the graph
    xg::XG index(graph);

    // Add in a thread
    vector<xg::XG::thread_t> threads {{
        {1, false},
        {2, false},
        {3, false},
        {5, false},
        {6, false},
        {7, false},
        {9, false}
    }, {
        {1, false},
        {2, false},
        {3, false},
        {5, false},
        {6, false},
        {7, false},
        {9, false}
    }, {
        {4, true}
    }};
    index.insert_threads_into_dag(threads, {});

    // Make a duplicator
    PhaseDuplicator duplicator(index);

    // Define a subgraph to duplicate out
    set<id_t> to_duplicate {2, 3, 4, 5};
    // And the next ID to use
    id_t next_id = 10;

    // Do the duplication
    pair<Graph, vector<Translation>> result(duplicator.duplicate(to_duplicate, next_id));
    Graph& duped = result.first;
    vector<Translation>& translations = result.second;

#ifdef debug
    cerr << pb2json(duped) << endl;
#endif

    // Check the result
    SECTION("the duplicated graph should have 4 nodes") {
        REQUIRE(duped.node_size() == 4);

        SECTION("the nodes should be A, T, T, and GGG") {
            bool a_found = false;
            bool ggg_found = false;
            for (size_t i = 0; i < duped.node_size(); i++) {
                auto& node = duped.node(i);
                if (node.sequence() == "A") {
                    REQUIRE(!a_found);
                    a_found = true;
                } else if (node.sequence() == "GGG") {
                    REQUIRE(!ggg_found);
                    ggg_found = true;
                } else {
                    REQUIRE(node.sequence() == "T");
                }
            }
            REQUIRE(a_found);
            REQUIRE(ggg_found);
        }
    }

    SECTION("the duplicated graph should have 4 edges") {
        REQUIRE(duped.edge_size() == 4);
    }
}

}
}
<commit_msg>fixed merge conflict in phase duplicator unit test<commit_after>/** \file
 *
 * Unit tests for the PhaseDuplicator, which replaces complex subgraphs with
 * observed traversals.
 */

#include <iostream>
#include "../phase_duplicator.hpp"
#include "../json2pb.h"

#include "catch.hpp"

namespace vg {
namespace unittest {

// Build a toy graph
const string duplicator_graph_1 = R"(
    {
        "node": [
            {"id": 1, "sequence": "G"},
            {"id": 2, "sequence": "A"},
            {"id": 3, "sequence": "T"},
            {"id": 4, "sequence": "GGG"},
            {"id": 5, "sequence": "T"},
            {"id": 6, "sequence": "A"},
            {"id": 7, "sequence": "C"},
            {"id": 8, "sequence": "A"},
            {"id": 9, "sequence": "A"}
        ],
        "edge": [
            {"from": 1, "to": 2},
            {"from": 1, "to": 6},
            {"from": 2, "to": 3},
            {"from": 2, "to": 4},
            {"from": 3, "to": 5},
            {"from": 4, "to": 5},
            {"from": 5, "to": 6},
            {"from": 6, "to": 7},
            {"from": 6, "to": 8},
            {"from": 7, "to": 9},
            {"from": 8, "to": 9}

        ],
        "path": [
            {"name": "hint", "mapping": [
                {"position": {"node_id": 1}, "rank" : 1 },
                {"position": {"node_id": 6}, "rank" : 2 },
                {"position": {"node_id": 8}, "rank" : 3 },
                {"position": {"node_id": 9}, "rank" : 4 }
            ]}
        ]
    }
    )";

TEST_CASE("PhaseDuplicator can emit a single traversal", "[phaseduplicator][indexing]") {

    // Make an actual graph
    Graph graph;
    json2pb(graph, duplicator_graph_1.c_str(), duplicator_graph_1.size());

    // Make an XG index of the graph
    xg::XG index(graph);

    // Add in a thread
    vector<xg::XG::thread_t> threads {{
        {1, false},
        {2, false},
        {3, false},
        {5, false},
        {6, false},
        {7, false},
        {9, false}
    }};
    index.insert_threads_into_dag(threads, {});

    // Make a duplicator
    PhaseDuplicator duplicator(index);

    // Define a subgraph to duplicate out
    set<id_t> to_duplicate {2, 3, 4, 5};
    // And the next ID to use
    id_t next_id = 10;

    // Do the duplication
    pair<Graph, vector<Translation>> result(duplicator.duplicate(to_duplicate, next_id));
    Graph& duped = result.first;
    vector<Translation>& translations = result.second;

#ifdef debug
    cerr << pb2json(duped) << endl;
#endif

    // Check the result
    SECTION("the duplicated graph should have 3 nodes") {
        REQUIRE(duped.node_size() == 3);

        SECTION("the nodes should be A, T, and T") {
            bool a_found = false;
            for (size_t i = 0; i < duped.node_size(); i++) {
                auto& node = duped.node(i);
                if (node.sequence() == "A") {
                    REQUIRE(!a_found);
                    a_found = true;
                } else {
                    REQUIRE(node.sequence() == "T");
                }
            }
            REQUIRE(a_found);
        }
    }

    SECTION("the duplicated graph should have 4 edges") {
        REQUIRE(duped.edge_size() == 4);
    }

    SECTION("there should be 1 translation") {
        REQUIRE(translations.size() == 1);

        auto& translation = translations.front();

        SECTION("the translation should have 3 mappings in each path") {
            REQUIRE(translation.from().mapping_size() == 3);
            REQUIRE(translation.to().mapping_size() == 3);

            SECTION("the from mappings should trace the original path") {
                REQUIRE(translation.from().mapping(0).position().node_id() == 2);
                REQUIRE(translation.from().mapping(0).position().is_reverse() == false);
                REQUIRE(translation.from().mapping(1).position().node_id() == 3);
                REQUIRE(translation.from().mapping(1).position().is_reverse() == false);
                REQUIRE(translation.from().mapping(2).position().node_id() == 5);
                REQUIRE(translation.from().mapping(2).position().is_reverse() == false);
            }

            SECTION("the to mappings should also spell out ATT") {
                // We need to index the duplicated nodes
                map<id_t, Node> id_to_node;
                for (size_t i = 0; i < duped.node_size(); i++) {
                    id_to_node[duped.node(i).id()] = duped.node(i);
                }

                for (size_t i = 0; i < translation.to().mapping_size(); i++) {
                    // All the mappings have to be to forward copies of these nodes.
                    auto& mapping = translation.to().mapping(i);
                    REQUIRE(id_to_node.count(mapping.position().node_id()));
                    REQUIRE(mapping.position().is_reverse() == false);
                }

                // And when we look at the nodes they need the right sequences
                REQUIRE(id_to_node[translation.to().mapping(0).position().node_id()].sequence() == "A");
                REQUIRE(id_to_node[translation.to().mapping(1).position().node_id()].sequence() == "T");
                REQUIRE(id_to_node[translation.to().mapping(2).position().node_id()].sequence() == "T");
            }
        }

    }

}

TEST_CASE("PhaseDuplicator can deduplicate identical traversals", "[phaseduplicator][indexing]") {

    // Make a graph

    // Make an actual graph
    Graph graph;
    json2pb(graph, duplicator_graph_1.c_str(), duplicator_graph_1.size());

    // Make an XG index of the graph
    xg::XG index(graph);

    // Add in a thread
    vector<xg::XG::thread_t> threads {{
        {1, false},
        {2, false},
        {3, false},
        {5, false},
        {6, false},
        {7, false},
        {9, false}
    }, {
        {1, false},
        {2, false},
        {3, false},
        {5, false},
        {6, false},
        {7, false},
        {9, false}
    }, {
        {9, true},
        {7, true},
        {6, true},
        {5, true},
        {3, true},
        {2, true},
        {1, true}
    }};
    index.insert_threads_into_dag(threads, {});

    // Make a duplicator
    PhaseDuplicator duplicator(index);

    // Define a subgraph to duplicate out
    set<id_t> to_duplicate {2, 3, 4, 5};
    // And the next ID to use
    id_t next_id = 10;

    // Do the duplication
    pair<Graph, vector<Translation>> result(duplicator.duplicate(to_duplicate, next_id));
    Graph& duped = result.first;
    vector<Translation>& translations = result.second;

#ifdef debug
    cerr << pb2json(duped) << endl;
#endif

    // Check the result
    SECTION("the duplicated graph should have 3 nodes") {
        REQUIRE(duped.node_size() == 3);

        SECTION("the nodes should be A, T, and T") {
            bool a_found = false;
            for (size_t i = 0; i < duped.node_size(); i++) {
                auto& node = duped.node(i);
                if (node.sequence() == "A") {
                    REQUIRE(!a_found);
                    a_found = true;
                } else {
                    REQUIRE(node.sequence() == "T");
                }
            }
            REQUIRE(a_found);
        }
    }

    SECTION("the duplicated graph should have 4 edges") {
        REQUIRE(duped.edge_size() == 4);
    }
}

TEST_CASE("PhaseDuplicator can produce internal traversals", "[phaseduplicator][indexing]") {

    // Make a graph

    // Make an actual graph
    Graph graph;
    json2pb(graph, duplicator_graph_1.c_str(), duplicator_graph_1.size());

    // Make an XG index of the graph
    xg::XG index(graph);

    // Add in a thread
    vector<xg::XG::thread_t> threads {{
        {1, false},
        {2, false},
        {3, false},
        {5, false},
        {6, false},
        {7, false},
        {9, false}
    }, {
        {1, false},
        {2, false},
        {3, false},
        {5, false},
        {6, false},
        {7, false},
        {9, false}
    }, {
        {4, true}
    }};
    index.insert_threads_into_dag(threads, {});

    // Make a duplicator
    PhaseDuplicator duplicator(index);

    // Define a subgraph to duplicate out
    set<id_t> to_duplicate {2, 3, 4, 5};
    // And the next ID to use
    id_t next_id = 10;

    // Do the duplication
    pair<Graph, vector<Translation>> result(duplicator.duplicate(to_duplicate, next_id));
    Graph& duped = result.first;
    vector<Translation>& translations = result.second;

#ifdef debug
    cerr << pb2json(duped) << endl;
#endif

    // Check the result
    SECTION("the duplicated graph should have 4 nodes") {
        REQUIRE(duped.node_size() == 4);

        SECTION("the nodes should be A, T, T, and GGG") {
            bool a_found = false;
            bool ggg_found = false;
            for (size_t i = 0; i < duped.node_size(); i++) {
                auto& node = duped.node(i);
                if (node.sequence() == "A") {
                    REQUIRE(!a_found);
                    a_found = true;
                } else if (node.sequence() == "GGG") {
                    REQUIRE(!ggg_found);
                    ggg_found = true;
                } else {
                    REQUIRE(node.sequence() == "T");
                }
            }
            REQUIRE(a_found);
            REQUIRE(ggg_found);
        }
    }

    SECTION("the duplicated graph should have 4 edges") {
        REQUIRE(duped.edge_size() == 4);
    }
}

}
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 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 "ash/drag_drop/drag_image_view.h"

#include "ui/views/widget/widget.h"

namespace ash {
namespace internal {

namespace {
using views::Widget;

Widget* CreateDragWidget() {
  Widget* drag_widget = new Widget;
  Widget::InitParams params;
  params.type = Widget::InitParams::TYPE_WINDOW_FRAMELESS;
  params.keep_on_top = true;
  params.accept_events = false;
  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  params.transparent = true;
  drag_widget->Init(params);
  drag_widget->SetOpacity(0xFF);
  return drag_widget;
}
}

DragImageView::DragImageView() : views::ImageView() {
  widget_.reset(CreateDragWidget());
  widget_->SetContentsView(this);
  widget_->SetAlwaysOnTop(true);

  // We are owned by the DragDropController.
  set_owned_by_client();
}

DragImageView::~DragImageView() {
  widget_->Hide();
}

void DragImageView::SetScreenBounds(const gfx::Rect& bounds) {
  widget_->SetBounds(bounds);
}

void DragImageView::SetScreenPosition(const gfx::Point& position) {
  widget_->SetBounds(gfx::Rect(position, GetPreferredSize()));
}

void DragImageView::SetWidgetVisible(bool visible) {
  if (visible != widget_->IsVisible()) {
    if (visible)
      widget_->Show();
    else
      widget_->Hide();
  }
}

}  // namespace internal
}  // namespace ash
<commit_msg>Revert 140320 - Revert 140315 - ash: Stack drag widget at the right order and fix its shadow.<commit_after>// Copyright (c) 2012 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 "ash/drag_drop/drag_image_view.h"

#include "ash/wm/shadow_types.h"
#include "ui/views/widget/widget.h"

namespace ash {
namespace internal {

namespace {
using views::Widget;

Widget* CreateDragWidget() {
  Widget* drag_widget = new Widget;
  Widget::InitParams params;
  params.type = Widget::InitParams::TYPE_TOOLTIP;
  params.keep_on_top = true;
  params.accept_events = false;
  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  params.transparent = true;
  drag_widget->Init(params);
  drag_widget->SetOpacity(0xFF);
  SetShadowType(drag_widget->GetNativeView(), SHADOW_TYPE_NONE);
  return drag_widget;
}
}

DragImageView::DragImageView() : views::ImageView() {
  widget_.reset(CreateDragWidget());
  widget_->SetContentsView(this);
  widget_->SetAlwaysOnTop(true);

  // We are owned by the DragDropController.
  set_owned_by_client();
}

DragImageView::~DragImageView() {
  widget_->Hide();
}

void DragImageView::SetScreenBounds(const gfx::Rect& bounds) {
  widget_->SetBounds(bounds);
}

void DragImageView::SetScreenPosition(const gfx::Point& position) {
  widget_->SetBounds(gfx::Rect(position, GetPreferredSize()));
}

void DragImageView::SetWidgetVisible(bool visible) {
  if (visible != widget_->IsVisible()) {
    if (visible)
      widget_->Show();
    else
      widget_->Hide();
  }
}

}  // namespace internal
}  // namespace ash
<|endoftext|>