<commit_before>/*
 * Copyright © 2014 Intel Corporation
 *
 * 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 (including the next
 * paragraph) 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 brw_fs_combine_constants.cpp
 *
 * This file contains the opt_combine_constants() pass that runs after the
 * regular optimization loop. It passes over the instruction list and
 * selectively promotes immediate values to registers by emitting a mov(1)
 * instruction.
 *
 * This is useful on Gen 7 particularly, because a few instructions can be
 * coissued (i.e., issued in the same cycle as another thread on the same EU
 * issues an instruction) under some circumstances, one of which is that they
 * cannot use immediate values.
 */

#include "brw_fs.h"
#include "brw_cfg.h"

using namespace brw;

/* Returns whether an instruction could co-issue if its immediate source were
 * replaced with a GRF source.
 */
static bool
could_coissue(const struct brw_device_info *devinfo, const fs_inst *inst)
{
   if (devinfo->gen != 7)
      return false;

   switch (inst->opcode) {
   case BRW_OPCODE_MOV:
   case BRW_OPCODE_CMP:
   case BRW_OPCODE_ADD:
   case BRW_OPCODE_MUL:
      return true;
   default:
      return false;
   }
}

/**
 * Returns true for instructions that don't support immediate sources.
 */
static bool
must_promote_imm(const struct brw_device_info *devinfo, const fs_inst *inst)
{
   switch (inst->opcode) {
   case SHADER_OPCODE_POW:
      return devinfo->gen < 8;
   case BRW_OPCODE_MAD:
   case BRW_OPCODE_LRP:
      return true;
   default:
      return false;
   }
}

/** A box for putting fs_regs in a linked list. */
struct reg_link {
   DECLARE_RALLOC_CXX_OPERATORS(reg_link)

   reg_link(fs_reg *reg) : reg(reg) {}

   struct exec_node link;
   fs_reg *reg;
};

static struct exec_node *
link(void *mem_ctx, fs_reg *reg)
{
   reg_link *l = new(mem_ctx) reg_link(reg);
   return &l->link;
}

/**
 * Information about an immediate value.
 */
struct imm {
   /** The common ancestor of all blocks using this immediate value. */
   bblock_t *block;

   /**
    * The instruction generating the immediate value, if all uses are contained
    * within a single basic block. Otherwise, NULL.
    */
   fs_inst *inst;

   /**
    * A list of fs_regs that refer to this immediate.  If we promote it, we'll
    * have to patch these up to refer to the new GRF.
    */
   exec_list *uses;

   /** The immediate value.  We currently only handle floats. */
   float val;

   /**
    * The GRF register and subregister number where we've decided to store the
    * constant value.
    */
   uint8_t subreg_offset;
   uint16_t nr;

   /** The number of coissuable instructions using this immediate. */
   uint16_t uses_by_coissue;

   /**
    * Whether this constant is used by an instruction that can't handle an
    * immediate source (and already has to be promoted to a GRF).
    */
   bool must_promote;

   uint16_t first_use_ip;
   uint16_t last_use_ip;
};

/** The working set of information about immediates. */
struct table {
   struct imm *imm;
   int size;
   int len;
};

static struct imm *
find_imm(struct table *table, float val)
{
   assert(signbit(val) == 0);

   for (int i = 0; i < table->len; i++) {
      if (table->imm[i].val == val) {
         return &table->imm[i];
      }
   }
   return NULL;
}

static struct imm *
new_imm(struct table *table, void *mem_ctx)
{
   if (table->len == table->size) {
      table->size *= 2;
      table->imm = reralloc(mem_ctx, table->imm, struct imm, table->size);
   }
   return &table->imm[table->len++];
}

/**
 * Comparator used for sorting an array of imm structures.
 *
 * We sort by basic block number, then last use IP, then first use IP (least
 * to greatest). This sorting causes immediates live in the same area to be
 * allocated to the same register in the hopes that all values will be dead
 * about the same time and the register can be reused.
 */
static int
compare(const void *_a, const void *_b)
{
   const struct imm *a = (const struct imm *)_a,
                    *b = (const struct imm *)_b;

   int block_diff = a->block->num - b->block->num;
   if (block_diff)
      return block_diff;

   int end_diff = a->last_use_ip - b->last_use_ip;
   if (end_diff)
      return end_diff;

   return a->first_use_ip - b->first_use_ip;
}

bool
fs_visitor::opt_combine_constants()
{
   void *const_ctx = ralloc_context(NULL);

   struct table table;
   table.size = 8;
   table.len = 0;
   table.imm = ralloc_array(const_ctx, struct imm, table.size);

   cfg->calculate_idom();
   unsigned ip = -1;

   /* Make a pass through all instructions and count the number of times each
    * constant is used by coissueable instructions or instructions that cannot
    * take immediate arguments.
    */
   foreach_block_and_inst(block, fs_inst, inst, cfg) {
      ip++;

      if (!could_coissue(devinfo, inst) && !must_promote_imm(devinfo, inst))
         continue;

      for (int i = 0; i < inst->sources; i++) {
         if (inst->src[i].file != IMM ||
             inst->src[i].type != BRW_REGISTER_TYPE_F)
            continue;

         float val = fabsf(inst->src[i].f);
         struct imm *imm = find_imm(&table, val);

         if (imm) {
            bblock_t *intersection = cfg_t::intersect(block, imm->block);
            if (intersection != imm->block)
               imm->inst = NULL;
            imm->block = intersection;
            imm->uses->push_tail(link(const_ctx, &inst->src[i]));
            imm->uses_by_coissue += could_coissue(devinfo, inst);
            imm->must_promote = imm->must_promote || must_promote_imm(devinfo, inst);
            imm->last_use_ip = ip;
         } else {
            imm = new_imm(&table, const_ctx);
            imm->block = block;
            imm->inst = inst;
            imm->uses = new(const_ctx) exec_list();
            imm->uses->push_tail(link(const_ctx, &inst->src[i]));
            imm->val = val;
            imm->uses_by_coissue = could_coissue(devinfo, inst);
            imm->must_promote = must_promote_imm(devinfo, inst);
            imm->first_use_ip = ip;
            imm->last_use_ip = ip;
         }
      }
   }

   /* Remove constants from the table that don't have enough uses to make them
    * profitable to store in a register.
    */
   for (int i = 0; i < table.len;) {
      struct imm *imm = &table.imm[i];

      if (!imm->must_promote && imm->uses_by_coissue < 4) {
         table.imm[i] = table.imm[table.len - 1];
         table.len--;
         continue;
      }
      i++;
   }
   if (table.len == 0) {
      ralloc_free(const_ctx);
      return false;
   }
   if (cfg->num_blocks != 1)
      qsort(table.imm, table.len, sizeof(struct imm), compare);

   /* Insert MOVs to load the constant values into GRFs. */
   fs_reg reg(VGRF, alloc.allocate(dispatch_width / 8));
   reg.stride = 0;
   for (int i = 0; i < table.len; i++) {
      struct imm *imm = &table.imm[i];
      /* Insert it either before the instruction that generated the immediate
       * or after the last non-control flow instruction of the common ancestor.
       */
      exec_node *n = (imm->inst ? imm->inst :
                      imm->block->last_non_control_flow_inst()->next);
      const fs_builder ibld = bld.at(imm->block, n).exec_all().group(1, 0);

      ibld.MOV(reg, brw_imm_f(imm->val));
      imm->nr = reg.nr;
      imm->subreg_offset = reg.subreg_offset;

      reg.subreg_offset += sizeof(float);
      if ((unsigned)reg.subreg_offset == dispatch_width * sizeof(float)) {
         reg.nr = alloc.allocate(dispatch_width / 8);
         reg.subreg_offset = 0;
      }
   }
   promoted_constants = table.len;

   /* Rewrite the immediate sources to refer to the new GRFs. */
   for (int i = 0; i < table.len; i++) {
      foreach_list_typed(reg_link, link, link, table.imm[i].uses) {
         fs_reg *reg = link->reg;
         reg->file = VGRF;
         reg->nr = table.imm[i].nr;
         reg->subreg_offset = table.imm[i].subreg_offset;
         reg->stride = 0;
         reg->negate = signbit(reg->f) != signbit(table.imm[i].val);
         assert(fabsf(reg->f) == table.imm[i].val);
      }
   }

   ralloc_free(const_ctx);
   invalidate_live_intervals();

   return true;
}
<commit_msg>i965/fs: Add debugging to constant combining pass.<commit_after>/*
 * Copyright © 2014 Intel Corporation
 *
 * 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 (including the next
 * paragraph) 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 brw_fs_combine_constants.cpp
 *
 * This file contains the opt_combine_constants() pass that runs after the
 * regular optimization loop. It passes over the instruction list and
 * selectively promotes immediate values to registers by emitting a mov(1)
 * instruction.
 *
 * This is useful on Gen 7 particularly, because a few instructions can be
 * coissued (i.e., issued in the same cycle as another thread on the same EU
 * issues an instruction) under some circumstances, one of which is that they
 * cannot use immediate values.
 */

#include "brw_fs.h"
#include "brw_cfg.h"

using namespace brw;

static const bool debug = false;

/* Returns whether an instruction could co-issue if its immediate source were
 * replaced with a GRF source.
 */
static bool
could_coissue(const struct brw_device_info *devinfo, const fs_inst *inst)
{
   if (devinfo->gen != 7)
      return false;

   switch (inst->opcode) {
   case BRW_OPCODE_MOV:
   case BRW_OPCODE_CMP:
   case BRW_OPCODE_ADD:
   case BRW_OPCODE_MUL:
      return true;
   default:
      return false;
   }
}

/**
 * Returns true for instructions that don't support immediate sources.
 */
static bool
must_promote_imm(const struct brw_device_info *devinfo, const fs_inst *inst)
{
   switch (inst->opcode) {
   case SHADER_OPCODE_POW:
      return devinfo->gen < 8;
   case BRW_OPCODE_MAD:
   case BRW_OPCODE_LRP:
      return true;
   default:
      return false;
   }
}

/** A box for putting fs_regs in a linked list. */
struct reg_link {
   DECLARE_RALLOC_CXX_OPERATORS(reg_link)

   reg_link(fs_reg *reg) : reg(reg) {}

   struct exec_node link;
   fs_reg *reg;
};

static struct exec_node *
link(void *mem_ctx, fs_reg *reg)
{
   reg_link *l = new(mem_ctx) reg_link(reg);
   return &l->link;
}

/**
 * Information about an immediate value.
 */
struct imm {
   /** The common ancestor of all blocks using this immediate value. */
   bblock_t *block;

   /**
    * The instruction generating the immediate value, if all uses are contained
    * within a single basic block. Otherwise, NULL.
    */
   fs_inst *inst;

   /**
    * A list of fs_regs that refer to this immediate.  If we promote it, we'll
    * have to patch these up to refer to the new GRF.
    */
   exec_list *uses;

   /** The immediate value.  We currently only handle floats. */
   float val;

   /**
    * The GRF register and subregister number where we've decided to store the
    * constant value.
    */
   uint8_t subreg_offset;
   uint16_t nr;

   /** The number of coissuable instructions using this immediate. */
   uint16_t uses_by_coissue;

   /**
    * Whether this constant is used by an instruction that can't handle an
    * immediate source (and already has to be promoted to a GRF).
    */
   bool must_promote;

   uint16_t first_use_ip;
   uint16_t last_use_ip;
};

/** The working set of information about immediates. */
struct table {
   struct imm *imm;
   int size;
   int len;
};

static struct imm *
find_imm(struct table *table, float val)
{
   assert(signbit(val) == 0);

   for (int i = 0; i < table->len; i++) {
      if (table->imm[i].val == val) {
         return &table->imm[i];
      }
   }
   return NULL;
}

static struct imm *
new_imm(struct table *table, void *mem_ctx)
{
   if (table->len == table->size) {
      table->size *= 2;
      table->imm = reralloc(mem_ctx, table->imm, struct imm, table->size);
   }
   return &table->imm[table->len++];
}

/**
 * Comparator used for sorting an array of imm structures.
 *
 * We sort by basic block number, then last use IP, then first use IP (least
 * to greatest). This sorting causes immediates live in the same area to be
 * allocated to the same register in the hopes that all values will be dead
 * about the same time and the register can be reused.
 */
static int
compare(const void *_a, const void *_b)
{
   const struct imm *a = (const struct imm *)_a,
                    *b = (const struct imm *)_b;

   int block_diff = a->block->num - b->block->num;
   if (block_diff)
      return block_diff;

   int end_diff = a->last_use_ip - b->last_use_ip;
   if (end_diff)
      return end_diff;

   return a->first_use_ip - b->first_use_ip;
}

bool
fs_visitor::opt_combine_constants()
{
   void *const_ctx = ralloc_context(NULL);

   struct table table;
   table.size = 8;
   table.len = 0;
   table.imm = ralloc_array(const_ctx, struct imm, table.size);

   cfg->calculate_idom();
   unsigned ip = -1;

   /* Make a pass through all instructions and count the number of times each
    * constant is used by coissueable instructions or instructions that cannot
    * take immediate arguments.
    */
   foreach_block_and_inst(block, fs_inst, inst, cfg) {
      ip++;

      if (!could_coissue(devinfo, inst) && !must_promote_imm(devinfo, inst))
         continue;

      for (int i = 0; i < inst->sources; i++) {
         if (inst->src[i].file != IMM ||
             inst->src[i].type != BRW_REGISTER_TYPE_F)
            continue;

         float val = fabsf(inst->src[i].f);
         struct imm *imm = find_imm(&table, val);

         if (imm) {
            bblock_t *intersection = cfg_t::intersect(block, imm->block);
            if (intersection != imm->block)
               imm->inst = NULL;
            imm->block = intersection;
            imm->uses->push_tail(link(const_ctx, &inst->src[i]));
            imm->uses_by_coissue += could_coissue(devinfo, inst);
            imm->must_promote = imm->must_promote || must_promote_imm(devinfo, inst);
            imm->last_use_ip = ip;
         } else {
            imm = new_imm(&table, const_ctx);
            imm->block = block;
            imm->inst = inst;
            imm->uses = new(const_ctx) exec_list();
            imm->uses->push_tail(link(const_ctx, &inst->src[i]));
            imm->val = val;
            imm->uses_by_coissue = could_coissue(devinfo, inst);
            imm->must_promote = must_promote_imm(devinfo, inst);
            imm->first_use_ip = ip;
            imm->last_use_ip = ip;
         }
      }
   }

   /* Remove constants from the table that don't have enough uses to make them
    * profitable to store in a register.
    */
   for (int i = 0; i < table.len;) {
      struct imm *imm = &table.imm[i];

      if (!imm->must_promote && imm->uses_by_coissue < 4) {
         table.imm[i] = table.imm[table.len - 1];
         table.len--;
         continue;
      }
      i++;
   }
   if (table.len == 0) {
      ralloc_free(const_ctx);
      return false;
   }
   if (cfg->num_blocks != 1)
      qsort(table.imm, table.len, sizeof(struct imm), compare);

   /* Insert MOVs to load the constant values into GRFs. */
   fs_reg reg(VGRF, alloc.allocate(dispatch_width / 8));
   reg.stride = 0;
   for (int i = 0; i < table.len; i++) {
      struct imm *imm = &table.imm[i];
      /* Insert it either before the instruction that generated the immediate
       * or after the last non-control flow instruction of the common ancestor.
       */
      exec_node *n = (imm->inst ? imm->inst :
                      imm->block->last_non_control_flow_inst()->next);
      const fs_builder ibld = bld.at(imm->block, n).exec_all().group(1, 0);

      ibld.MOV(reg, brw_imm_f(imm->val));
      imm->nr = reg.nr;
      imm->subreg_offset = reg.subreg_offset;

      reg.subreg_offset += sizeof(float);
      if ((unsigned)reg.subreg_offset == dispatch_width * sizeof(float)) {
         reg.nr = alloc.allocate(dispatch_width / 8);
         reg.subreg_offset = 0;
      }
   }
   promoted_constants = table.len;

   /* Rewrite the immediate sources to refer to the new GRFs. */
   for (int i = 0; i < table.len; i++) {
      foreach_list_typed(reg_link, link, link, table.imm[i].uses) {
         fs_reg *reg = link->reg;
         reg->file = VGRF;
         reg->nr = table.imm[i].nr;
         reg->subreg_offset = table.imm[i].subreg_offset;
         reg->stride = 0;
         reg->negate = signbit(reg->f) != signbit(table.imm[i].val);
         assert(fabsf(reg->f) == table.imm[i].val);
      }
   }

   if (debug) {
      for (int i = 0; i < table.len; i++) {
         struct imm *imm = &table.imm[i];

         printf("%.3fF - block %3d, reg %3d sub %2d, Uses: (%2d, %2d), "
                "IP: %4d to %4d, length %4d\n",
                imm->val,
                imm->block->num,
                imm->nr,
                imm->subreg_offset,
                imm->must_promote,
                imm->uses_by_coissue,
                imm->first_use_ip,
                imm->last_use_ip,
                imm->last_use_ip - imm->first_use_ip);
      }
   }

   ralloc_free(const_ctx);
   invalidate_live_intervals();

   return true;
}
<|endoftext|>


<commit_before>// Copyright 2014 Toggl Desktop developers.

#include "./https_client.h"

#include <string>
#include <sstream>

#include "Poco/Exception.h"
#include "Poco/InflatingStream.h"
#include "Poco/DeflatingStream.h"
#include "Poco/Logger.h"
#include "Poco/URI.h"
#include "Poco/NumberParser.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/NameValueCollection.h"
#include "Poco/Net/HTTPMessage.h"
#include "Poco/Net/HTTPBasicCredentials.h"
#include "Poco/Net/InvalidCertificateHandler.h"
#include "Poco/Net/AcceptCertificateHandler.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
#include "Poco/Net/SecureStreamSocket.h"

#include "./libjson.h"
#include "./const.h"

namespace kopsik {

std::string HTTPSClient::AppName = std::string("");
std::string HTTPSClient::AppVersion = std::string("");
std::string HTTPSClient::APIURL = std::string(kAPIURL);
bool HTTPSClient::UseProxy = false;
bool HTTPSClient::IgnoreCert = false;
kopsik::Proxy HTTPSClient::ProxySettings = Proxy();

error HTTPSClient::PostJSON(
    const std::string relative_url,
    const std::string json,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
    return requestJSON(Poco::Net::HTTPRequest::HTTP_POST,
                       relative_url,
                       json,
                       basic_auth_username,
                       basic_auth_password,
                       response_body);
}

error HTTPSClient::GetJSON(
    const std::string relative_url,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
    return requestJSON(Poco::Net::HTTPRequest::HTTP_GET,
                       relative_url,
                       "",
                       basic_auth_username,
                       basic_auth_password,
                       response_body);
}

error HTTPSClient::requestJSON(
    const std::string method,
    const std::string relative_url,
    const std::string json,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
    return request(
        method,
        relative_url,
        json,
        basic_auth_username,
        basic_auth_password,
        response_body);
}

error HTTPSClient::request(
    const std::string method,
    const std::string relative_url,
    const std::string payload,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {

    poco_assert(!method.empty());
    poco_assert(!relative_url.empty());

    poco_check_ptr(response_body);

    *response_body = "";

    try {
        Poco::URI uri(APIURL);

        Poco::SharedPtr<Poco::Net::InvalidCertificateHandler>
        acceptCertHandler =
            new Poco::Net::AcceptCertificateHandler(true);

        Poco::Net::Context::VerificationMode verification_mode =
            Poco::Net::Context::VERIFY_RELAXED;
        if (IgnoreCert) {
            verification_mode = Poco::Net::Context::VERIFY_NONE;
        }
        Poco::Net::Context::Ptr context = new Poco::Net::Context(
            Poco::Net::Context::CLIENT_USE, "",
            verification_mode, 9, true, "ALL");

        Poco::Net::SSLManager::instance().initializeClient(
            0, acceptCertHandler, context);

        Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort(),
                                              context);
        if (ProxySettings.IsConfigured()) {
            session.setProxy(ProxySettings.host, ProxySettings.port);
            if (ProxySettings.HasCredentials()) {
                session.setProxyCredentials(ProxySettings.username,
                                            ProxySettings.password);
            }
        }
        session.setKeepAlive(false);
        session.setTimeout(Poco::Timespan(10 * Poco::Timespan::SECONDS));

        Poco::Logger &logger = Poco::Logger::get("https_client");
        {
            std::stringstream ss;
            ss << "Sending request to " << relative_url << " ..";
            logger.debug(ss.str());
        }

        Poco::Net::HTTPRequest req(method,
                                   relative_url,
                                   Poco::Net::HTTPMessage::HTTP_1_1);
        req.setKeepAlive(false);
        req.setContentType("application/json");
        req.set("User-Agent", UserAgent());
        req.setChunkedTransferEncoding(true);

        Poco::Net::HTTPBasicCredentials cred(
            basic_auth_username, basic_auth_password);
        if (!basic_auth_username.empty() && !basic_auth_password.empty()) {
            cred.authenticate(req);
        }

        std::istringstream requestStream(payload);
        Poco::DeflatingInputStream gzipRequest(
            requestStream,
            Poco::DeflatingStreamBuf::STREAM_GZIP);
        Poco::DeflatingStreamBuf *pBuff = gzipRequest.rdbuf();

        Poco::Int64 size = pBuff->pubseekoff(0, std::ios::end, std::ios::in);
        pBuff->pubseekpos(0, std::ios::in);

        req.setContentLength(size);
        req.set("Content-Encoding", "gzip");
        req.set("Accept-Encoding", "gzip");

        session.sendRequest(req) << pBuff << std::flush;

        // Log out request contents
        std::stringstream request_string;
        req.write(request_string);
        logger.debug(request_string.str());

        logger.debug("Request sent. Receiving response..");

        // Receive response
        Poco::Net::HTTPResponse response;
        std::istream& is = session.receiveResponse(response);

        {
            std::stringstream ss;
            ss << "Response content length " << response.getContentLength()
               << ", content type " << response.getContentType();
            if (response.has("Content-Encoding")) {
                ss << ", content encoding " << response.get("Content-Encoding");
            } else {
                ss << ", unknown content encoding";
            }
            logger.debug(ss.str());
        }

        // Inflate, if gzip was sent
        if (response.has("Content-Encoding") &&
                "gzip" == response.get("Content-Encoding")) {
            Poco::InflatingInputStream inflater(
                is,
                Poco::InflatingStreamBuf::STREAM_GZIP);
            {
                std::stringstream ss;
                ss << inflater.rdbuf();
                *response_body = ss.str();
            }
        } else {
            std::istreambuf_iterator<char> eos;
            *response_body =
                std::string(std::istreambuf_iterator<char>(is), eos);
        }

        logger.trace(*response_body);

        if (response.getStatus() < 200 || response.getStatus() >= 300) {
            if (response_body->empty()) {
                std::stringstream description;
                description << "Request to server failed with status code: "
                            << response.getStatus();
                return description.str();
            }
            return "Data push failed with error: " + *response_body;
        }
    } catch(const Poco::Exception& exc) {
        return exc.displayText();
    } catch(const std::exception& ex) {
        return ex.what();
    } catch(const std::string& ex) {
        return ex;
    }
    return noError;
}

}   // namespace kopsik
<commit_msg>Better wording for failing requests<commit_after>// Copyright 2014 Toggl Desktop developers.

#include "./https_client.h"

#include <string>
#include <sstream>

#include "Poco/Exception.h"
#include "Poco/InflatingStream.h"
#include "Poco/DeflatingStream.h"
#include "Poco/Logger.h"
#include "Poco/URI.h"
#include "Poco/NumberParser.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/NameValueCollection.h"
#include "Poco/Net/HTTPMessage.h"
#include "Poco/Net/HTTPBasicCredentials.h"
#include "Poco/Net/InvalidCertificateHandler.h"
#include "Poco/Net/AcceptCertificateHandler.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
#include "Poco/Net/SecureStreamSocket.h"

#include "./libjson.h"
#include "./const.h"

namespace kopsik {

std::string HTTPSClient::AppName = std::string("");
std::string HTTPSClient::AppVersion = std::string("");
std::string HTTPSClient::APIURL = std::string(kAPIURL);
bool HTTPSClient::UseProxy = false;
bool HTTPSClient::IgnoreCert = false;
kopsik::Proxy HTTPSClient::ProxySettings = Proxy();

error HTTPSClient::PostJSON(
    const std::string relative_url,
    const std::string json,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
    return requestJSON(Poco::Net::HTTPRequest::HTTP_POST,
                       relative_url,
                       json,
                       basic_auth_username,
                       basic_auth_password,
                       response_body);
}

error HTTPSClient::GetJSON(
    const std::string relative_url,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
    return requestJSON(Poco::Net::HTTPRequest::HTTP_GET,
                       relative_url,
                       "",
                       basic_auth_username,
                       basic_auth_password,
                       response_body);
}

error HTTPSClient::requestJSON(
    const std::string method,
    const std::string relative_url,
    const std::string json,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
    return request(
        method,
        relative_url,
        json,
        basic_auth_username,
        basic_auth_password,
        response_body);
}

error HTTPSClient::request(
    const std::string method,
    const std::string relative_url,
    const std::string payload,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {

    poco_assert(!method.empty());
    poco_assert(!relative_url.empty());

    poco_check_ptr(response_body);

    *response_body = "";

    try {
        Poco::URI uri(APIURL);

        Poco::SharedPtr<Poco::Net::InvalidCertificateHandler>
        acceptCertHandler =
            new Poco::Net::AcceptCertificateHandler(true);

        Poco::Net::Context::VerificationMode verification_mode =
            Poco::Net::Context::VERIFY_RELAXED;
        if (IgnoreCert) {
            verification_mode = Poco::Net::Context::VERIFY_NONE;
        }
        Poco::Net::Context::Ptr context = new Poco::Net::Context(
            Poco::Net::Context::CLIENT_USE, "",
            verification_mode, 9, true, "ALL");

        Poco::Net::SSLManager::instance().initializeClient(
            0, acceptCertHandler, context);

        Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort(),
                                              context);
        if (ProxySettings.IsConfigured()) {
            session.setProxy(ProxySettings.host, ProxySettings.port);
            if (ProxySettings.HasCredentials()) {
                session.setProxyCredentials(ProxySettings.username,
                                            ProxySettings.password);
            }
        }
        session.setKeepAlive(false);
        session.setTimeout(Poco::Timespan(10 * Poco::Timespan::SECONDS));

        Poco::Logger &logger = Poco::Logger::get("https_client");
        {
            std::stringstream ss;
            ss << "Sending request to " << relative_url << " ..";
            logger.debug(ss.str());
        }

        Poco::Net::HTTPRequest req(method,
                                   relative_url,
                                   Poco::Net::HTTPMessage::HTTP_1_1);
        req.setKeepAlive(false);
        req.setContentType("application/json");
        req.set("User-Agent", UserAgent());
        req.setChunkedTransferEncoding(true);

        Poco::Net::HTTPBasicCredentials cred(
            basic_auth_username, basic_auth_password);
        if (!basic_auth_username.empty() && !basic_auth_password.empty()) {
            cred.authenticate(req);
        }

        std::istringstream requestStream(payload);
        Poco::DeflatingInputStream gzipRequest(
            requestStream,
            Poco::DeflatingStreamBuf::STREAM_GZIP);
        Poco::DeflatingStreamBuf *pBuff = gzipRequest.rdbuf();

        Poco::Int64 size = pBuff->pubseekoff(0, std::ios::end, std::ios::in);
        pBuff->pubseekpos(0, std::ios::in);

        req.setContentLength(size);
        req.set("Content-Encoding", "gzip");
        req.set("Accept-Encoding", "gzip");

        session.sendRequest(req) << pBuff << std::flush;

        // Log out request contents
        std::stringstream request_string;
        req.write(request_string);
        logger.debug(request_string.str());

        logger.debug("Request sent. Receiving response..");

        // Receive response
        Poco::Net::HTTPResponse response;
        std::istream& is = session.receiveResponse(response);

        {
            std::stringstream ss;
            ss << "Response status code " << response.getStatus()
               << ", content length " << response.getContentLength()
               << ", content type " << response.getContentType();
            if (response.has("Content-Encoding")) {
                ss << ", content encoding " << response.get("Content-Encoding");
            } else {
                ss << ", unknown content encoding";
            }
            logger.debug(ss.str());
        }

        // Inflate, if gzip was sent
        if (response.has("Content-Encoding") &&
                "gzip" == response.get("Content-Encoding")) {
            Poco::InflatingInputStream inflater(
                is,
                Poco::InflatingStreamBuf::STREAM_GZIP);
            {
                std::stringstream ss;
                ss << inflater.rdbuf();
                *response_body = ss.str();
            }
        } else {
            std::istreambuf_iterator<char> eos;
            *response_body =
                std::string(std::istreambuf_iterator<char>(is), eos);
        }

        logger.trace(*response_body);

        if (response.getStatus() < 200 || response.getStatus() >= 300) {
            if (response_body->empty()) {
                std::stringstream description;
                description << "Request to server failed with status code: "
                            << response.getStatus();
                return description.str();
            }
            return "Request failed with error: " + *response_body;
        }
    } catch(const Poco::Exception& exc) {
        return exc.displayText();
    } catch(const std::exception& ex) {
        return ex.what();
    } catch(const std::string& ex) {
        return ex;
    }
    return noError;
}

}   // namespace kopsik
<|endoftext|>


<commit_before>/*
 * Copyright © 2012 Intel Corporation
 *
 * 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 (including the next
 * paragraph) 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 brw_fs_register_coalesce.cpp
 *
 * Implements register coalescing: Checks if the two registers involved in a
 * raw move don't interfere, in which case they can both be stored in the same
 * place and the MOV removed.
 *
 * To do this, all uses of the source of the MOV in the shader are replaced
 * with the destination of the MOV. For example:
 *
 * add vgrf3:F, vgrf1:F, vgrf2:F
 * mov vgrf4:F, vgrf3:F
 * mul vgrf5:F, vgrf5:F, vgrf4:F
 *
 * becomes
 *
 * add vgrf4:F, vgrf1:F, vgrf2:F
 * mul vgrf5:F, vgrf5:F, vgrf4:F
 */

#include "brw_fs.h"
#include "brw_fs_live_variables.h"

static bool
is_nop_mov(const fs_inst *inst)
{
   if (inst->opcode == BRW_OPCODE_MOV) {
      return inst->dst.equals(inst->src[0]);
   }

   return false;
}

static bool
is_coalesce_candidate(const fs_inst *inst, const int *virtual_grf_sizes)
{
   if (inst->opcode != BRW_OPCODE_MOV ||
       inst->is_partial_write() ||
       inst->saturate ||
       inst->src[0].file != GRF ||
       inst->src[0].negate ||
       inst->src[0].abs ||
       !inst->src[0].is_contiguous() ||
       inst->dst.file != GRF ||
       inst->dst.type != inst->src[0].type) {
      return false;
   }

   if (virtual_grf_sizes[inst->src[0].reg] >
       virtual_grf_sizes[inst->dst.reg])
      return false;

   return true;
}

static bool
can_coalesce_vars(brw::fs_live_variables *live_intervals,
                  const exec_list *instructions, const fs_inst *inst,
                  int var_to, int var_from)
{
   if (!live_intervals->vars_interfere(var_from, var_to))
      return true;

   /* We know that the live ranges of A (var_from) and B (var_to)
    * interfere because of the ->vars_interfere() call above. If the end
    * of B's live range is after the end of A's range, then we know two
    * things:
    *  - the start of B's live range must be in A's live range (since we
    *    already know the two ranges interfere, this is the only remaining
    *    possibility)
    *  - the interference isn't of the form we're looking for (where B is
    *    entirely inside A)
    */
   if (live_intervals->end[var_to] > live_intervals->end[var_from])
      return false;

   int scan_ip = -1;

   foreach_list(n, instructions) {
      fs_inst *scan_inst = (fs_inst *)n;
      scan_ip++;

      if (scan_inst->is_control_flow())
         return false;

      if (scan_ip <= live_intervals->start[var_to])
         continue;

      if (scan_ip > live_intervals->end[var_to])
         break;

      if (scan_inst->dst.equals(inst->dst) ||
          scan_inst->dst.equals(inst->src[0]))
         return false;
   }

   return true;
}

bool
fs_visitor::register_coalesce()
{
   bool progress = false;

   calculate_live_intervals();

   int src_size = 0;
   int channels_remaining = 0;
   int reg_from = -1, reg_to = -1;
   int reg_to_offset[MAX_SAMPLER_MESSAGE_SIZE];
   fs_inst *mov[MAX_SAMPLER_MESSAGE_SIZE];
   int var_to[MAX_SAMPLER_MESSAGE_SIZE];
   int var_from[MAX_SAMPLER_MESSAGE_SIZE];

   foreach_list(node, &this->instructions) {
      fs_inst *inst = (fs_inst *)node;

      if (!is_coalesce_candidate(inst, virtual_grf_sizes))
         continue;

      if (is_nop_mov(inst)) {
         inst->opcode = BRW_OPCODE_NOP;
         progress = true;
         continue;
      }

      if (reg_from != inst->src[0].reg) {
         reg_from = inst->src[0].reg;

         src_size = virtual_grf_sizes[inst->src[0].reg];
         assert(src_size <= MAX_SAMPLER_MESSAGE_SIZE);

         channels_remaining = src_size;
         memset(mov, 0, sizeof(mov));

         reg_to = inst->dst.reg;
      }

      if (reg_to != inst->dst.reg)
         continue;

      const int offset = inst->src[0].reg_offset;
      reg_to_offset[offset] = inst->dst.reg_offset;
      mov[offset] = inst;
      channels_remaining--;

      if (channels_remaining)
         continue;

      bool can_coalesce = true;
      for (int i = 0; i < src_size; i++) {
         var_to[i] = live_intervals->var_from_vgrf[reg_to] + reg_to_offset[i];
         var_from[i] = live_intervals->var_from_vgrf[reg_from] + i;

         if (!can_coalesce_vars(live_intervals, &instructions, inst,
                                var_to[i], var_from[i])) {
            can_coalesce = false;
            reg_from = -1;
            break;
         }
      }

      if (!can_coalesce)
         continue;

      progress = true;

      for (int i = 0; i < src_size; i++) {
         if (mov[i]) {
            mov[i]->opcode = BRW_OPCODE_NOP;
            mov[i]->conditional_mod = BRW_CONDITIONAL_NONE;
            mov[i]->dst = reg_undef;
            mov[i]->src[0] = reg_undef;
            mov[i]->src[1] = reg_undef;
            mov[i]->src[2] = reg_undef;
         }
      }

      foreach_list(node, &this->instructions) {
         fs_inst *scan_inst = (fs_inst *)node;

         for (int i = 0; i < src_size; i++) {
            if (mov[i]) {
               if (scan_inst->dst.file == GRF &&
                   scan_inst->dst.reg == reg_from &&
                   scan_inst->dst.reg_offset == i) {
                  scan_inst->dst.reg = reg_to;
                  scan_inst->dst.reg_offset = reg_to_offset[i];
               }
               for (int j = 0; j < 3; j++) {
                  if (scan_inst->src[j].file == GRF &&
                      scan_inst->src[j].reg == reg_from &&
                      scan_inst->src[j].reg_offset == i) {
                     scan_inst->src[j].reg = reg_to;
                     scan_inst->src[j].reg_offset = reg_to_offset[i];
                  }
               }
            }
         }
      }

      for (int i = 0; i < src_size; i++) {
         live_intervals->start[var_to[i]] =
            MIN2(live_intervals->start[var_to[i]],
                 live_intervals->start[var_from[i]]);
         live_intervals->end[var_to[i]] =
            MAX2(live_intervals->end[var_to[i]],
                 live_intervals->end[var_from[i]]);
      }
      reg_from = -1;
   }

   if (progress) {
      foreach_list_safe(node, &this->instructions) {
         fs_inst *inst = (fs_inst *)node;

         if (inst->opcode == BRW_OPCODE_NOP) {
            inst->remove();
         }
      }

      invalidate_live_intervals();
   }

   return progress;
}
<commit_msg>i965/fs: Simplify interference scan in register coalescing.<commit_after>/*
 * Copyright © 2012 Intel Corporation
 *
 * 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 (including the next
 * paragraph) 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 brw_fs_register_coalesce.cpp
 *
 * Implements register coalescing: Checks if the two registers involved in a
 * raw move don't interfere, in which case they can both be stored in the same
 * place and the MOV removed.
 *
 * To do this, all uses of the source of the MOV in the shader are replaced
 * with the destination of the MOV. For example:
 *
 * add vgrf3:F, vgrf1:F, vgrf2:F
 * mov vgrf4:F, vgrf3:F
 * mul vgrf5:F, vgrf5:F, vgrf4:F
 *
 * becomes
 *
 * add vgrf4:F, vgrf1:F, vgrf2:F
 * mul vgrf5:F, vgrf5:F, vgrf4:F
 */

#include "brw_fs.h"
#include "brw_fs_live_variables.h"

static bool
is_nop_mov(const fs_inst *inst)
{
   if (inst->opcode == BRW_OPCODE_MOV) {
      return inst->dst.equals(inst->src[0]);
   }

   return false;
}

static bool
is_coalesce_candidate(const fs_inst *inst, const int *virtual_grf_sizes)
{
   if (inst->opcode != BRW_OPCODE_MOV ||
       inst->is_partial_write() ||
       inst->saturate ||
       inst->src[0].file != GRF ||
       inst->src[0].negate ||
       inst->src[0].abs ||
       !inst->src[0].is_contiguous() ||
       inst->dst.file != GRF ||
       inst->dst.type != inst->src[0].type) {
      return false;
   }

   if (virtual_grf_sizes[inst->src[0].reg] >
       virtual_grf_sizes[inst->dst.reg])
      return false;

   return true;
}

static bool
can_coalesce_vars(brw::fs_live_variables *live_intervals,
                  const exec_list *instructions, const fs_inst *inst, int ip,
                  int var_to, int var_from)
{
   if (!live_intervals->vars_interfere(var_from, var_to))
      return true;

   /* We know that the live ranges of A (var_from) and B (var_to)
    * interfere because of the ->vars_interfere() call above. If the end
    * of B's live range is after the end of A's range, then we know two
    * things:
    *  - the start of B's live range must be in A's live range (since we
    *    already know the two ranges interfere, this is the only remaining
    *    possibility)
    *  - the interference isn't of the form we're looking for (where B is
    *    entirely inside A)
    */
   if (live_intervals->end[var_to] > live_intervals->end[var_from])
      return false;

   assert(ip >= live_intervals->start[var_to]);

   fs_inst *scan_inst;
   for (scan_inst = (fs_inst *)inst->next;
        !scan_inst->is_tail_sentinel() && ip <= live_intervals->end[var_to];
        scan_inst = (fs_inst *)scan_inst->next, ip++) {
      if (scan_inst->is_control_flow())
         return false;

      if (scan_inst->dst.equals(inst->dst) ||
          scan_inst->dst.equals(inst->src[0]))
         return false;
   }

   return true;
}

bool
fs_visitor::register_coalesce()
{
   bool progress = false;

   calculate_live_intervals();

   int src_size = 0;
   int channels_remaining = 0;
   int reg_from = -1, reg_to = -1;
   int reg_to_offset[MAX_SAMPLER_MESSAGE_SIZE];
   fs_inst *mov[MAX_SAMPLER_MESSAGE_SIZE];
   int var_to[MAX_SAMPLER_MESSAGE_SIZE];
   int var_from[MAX_SAMPLER_MESSAGE_SIZE];
   int ip = -1;

   foreach_list(node, &this->instructions) {
      fs_inst *inst = (fs_inst *)node;
      ip++;

      if (!is_coalesce_candidate(inst, virtual_grf_sizes))
         continue;

      if (is_nop_mov(inst)) {
         inst->opcode = BRW_OPCODE_NOP;
         progress = true;
         continue;
      }

      if (reg_from != inst->src[0].reg) {
         reg_from = inst->src[0].reg;

         src_size = virtual_grf_sizes[inst->src[0].reg];
         assert(src_size <= MAX_SAMPLER_MESSAGE_SIZE);

         channels_remaining = src_size;
         memset(mov, 0, sizeof(mov));

         reg_to = inst->dst.reg;
      }

      if (reg_to != inst->dst.reg)
         continue;

      const int offset = inst->src[0].reg_offset;
      reg_to_offset[offset] = inst->dst.reg_offset;
      mov[offset] = inst;
      channels_remaining--;

      if (channels_remaining)
         continue;

      bool can_coalesce = true;
      for (int i = 0; i < src_size; i++) {
         var_to[i] = live_intervals->var_from_vgrf[reg_to] + reg_to_offset[i];
         var_from[i] = live_intervals->var_from_vgrf[reg_from] + i;

         if (!can_coalesce_vars(live_intervals, &instructions, inst, ip,
                                var_to[i], var_from[i])) {
            can_coalesce = false;
            reg_from = -1;
            break;
         }
      }

      if (!can_coalesce)
         continue;

      progress = true;

      for (int i = 0; i < src_size; i++) {
         if (mov[i]) {
            mov[i]->opcode = BRW_OPCODE_NOP;
            mov[i]->conditional_mod = BRW_CONDITIONAL_NONE;
            mov[i]->dst = reg_undef;
            mov[i]->src[0] = reg_undef;
            mov[i]->src[1] = reg_undef;
            mov[i]->src[2] = reg_undef;
         }
      }

      foreach_list(node, &this->instructions) {
         fs_inst *scan_inst = (fs_inst *)node;

         for (int i = 0; i < src_size; i++) {
            if (mov[i]) {
               if (scan_inst->dst.file == GRF &&
                   scan_inst->dst.reg == reg_from &&
                   scan_inst->dst.reg_offset == i) {
                  scan_inst->dst.reg = reg_to;
                  scan_inst->dst.reg_offset = reg_to_offset[i];
               }
               for (int j = 0; j < 3; j++) {
                  if (scan_inst->src[j].file == GRF &&
                      scan_inst->src[j].reg == reg_from &&
                      scan_inst->src[j].reg_offset == i) {
                     scan_inst->src[j].reg = reg_to;
                     scan_inst->src[j].reg_offset = reg_to_offset[i];
                  }
               }
            }
         }
      }

      for (int i = 0; i < src_size; i++) {
         live_intervals->start[var_to[i]] =
            MIN2(live_intervals->start[var_to[i]],
                 live_intervals->start[var_from[i]]);
         live_intervals->end[var_to[i]] =
            MAX2(live_intervals->end[var_to[i]],
                 live_intervals->end[var_from[i]]);
      }
      reg_from = -1;
   }

   if (progress) {
      foreach_list_safe(node, &this->instructions) {
         fs_inst *inst = (fs_inst *)node;

         if (inst->opcode == BRW_OPCODE_NOP) {
            inst->remove();
         }
      }

      invalidate_live_intervals();
   }

   return progress;
}
<|endoftext|>


<commit_before>//===-- tsan_suppressions.cc ------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//

#include "tsan_suppressions.h"
#include "tsan_rtl.h"
#include "tsan_flags.h"
#include "tsan_mman.h"
#include "tsan_platform.h"

namespace __tsan {

static Suppression *g_suppressions;

static char *ReadFile(const char *filename) {
  if (filename == 0 || filename[0] == 0)
    return 0;
  InternalScopedBuf<char> tmp(4*1024);
  if (filename[0] == '/')
    Snprintf(tmp, tmp.Size(), "%s", filename);
  else
    Snprintf(tmp, tmp.Size(), "%s/%s", internal_getpwd(), filename);
  fd_t fd = internal_open(tmp, false);
  if (fd == kInvalidFd) {
    Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
        tmp.Ptr());
    Die();
  }
  const uptr fsize = internal_filesize(fd);
  if (fsize == (uptr)-1) {
    Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
        tmp.Ptr());
    Die();
  }
  char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
  if (fsize != internal_read(fd, buf, fsize)) {
    Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
        tmp.Ptr());
    Die();
  }
  internal_close(fd);
  buf[fsize] = 0;
  return buf;
}

bool SuppressionMatch(char *templ, const char *str) {
  if (str == 0 || str[0] == 0)
    return false;
  char *tpos;
  const char *spos;
  while (templ && templ[0]) {
    if (templ[0] == '*') {
      templ++;
      continue;
    }
    if (str[0] == 0)
      return false;
    tpos = (char*)internal_strchr(templ, '*');
    if (tpos != 0)
      tpos[0] = 0;
    spos = internal_strstr(str, templ);
    str = spos + internal_strlen(templ);
    templ = tpos;
    if (tpos)
      tpos[0] = '*';
    if (spos == 0)
      return false;
  }
  return true;
}

Suppression *SuppressionParse(const char* supp) {
  Suppression *head = 0;
  const char *line = supp;
  while (line) {
    while (line[0] == ' ' || line[0] == '\t')
      line++;
    const char *end = internal_strchr(line, '\n');
    if (end == 0)
      end = line + internal_strlen(line);
    if (line != end && line[0] != '#') {
      const char *end2 = end;
      while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
        end2--;
      SuppressionType stype;
      if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
        stype = SuppressionRace;
        line += sizeof("race:") - 1;
      } else if (0 == internal_strncmp(line, "thread:",
          sizeof("thread:") - 1)) {
        stype = SuppressionThread;
        line += sizeof("thread:") - 1;
      } else if (0 == internal_strncmp(line, "mutex:",
          sizeof("mutex:") - 1)) {
        stype = SuppressionMutex;
        line += sizeof("mutex:") - 1;
      } else if (0 == internal_strncmp(line, "signal:",
          sizeof("signal:") - 1)) {
        stype = SuppressionSignal;
        line += sizeof("signal:") - 1;
      } else {
        Printf("ThreadSanitizer: failed to parse suppressions file\n");
        Die();
      }
      Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
          sizeof(Suppression));
      s->next = head;
      head = s;
      s->type = stype;
      s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
      internal_memcpy(s->templ, line, end2 - line);
      s->templ[end2 - line] = 0;
    }
    if (end[0] == 0)
      break;
    line = end + 1;
  }
  return head;
}

void InitializeSuppressions() {
  char *supp = ReadFile(flags()->suppressions);
  g_suppressions = SuppressionParse(supp);
}

bool IsSuppressed(ReportType typ, const ReportStack *stack) {
  if (g_suppressions == 0 || stack == 0)
    return false;
  SuppressionType stype;
  if (typ == ReportTypeRace)
    stype = SuppressionRace;
  else if (typ == ReportTypeThreadLeak)
    stype = SuppressionThread;
  else if (typ == ReportTypeMutexDestroyLocked)
    stype = SuppressionMutex;
  else if (typ == ReportTypeSignalUnsafe)
    stype = SuppressionSignal;
  else
    return false;
  for (const ReportStack *frame = stack; frame; frame = frame->next) {
    for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
      if (stype == supp->type ||
          SuppressionMatch(supp->templ, frame->func) ||
          SuppressionMatch(supp->templ, frame->file)) {
        DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
        return true;
      }
    }
  }
  return false;
}
}  // namespace __tsan
<commit_msg>tsan: fix a typo<commit_after>//===-- tsan_suppressions.cc ------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//

#include "tsan_suppressions.h"
#include "tsan_rtl.h"
#include "tsan_flags.h"
#include "tsan_mman.h"
#include "tsan_platform.h"

namespace __tsan {

static Suppression *g_suppressions;

static char *ReadFile(const char *filename) {
  if (filename == 0 || filename[0] == 0)
    return 0;
  InternalScopedBuf<char> tmp(4*1024);
  if (filename[0] == '/')
    Snprintf(tmp, tmp.Size(), "%s", filename);
  else
    Snprintf(tmp, tmp.Size(), "%s/%s", internal_getpwd(), filename);
  fd_t fd = internal_open(tmp, false);
  if (fd == kInvalidFd) {
    Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
        tmp.Ptr());
    Die();
  }
  const uptr fsize = internal_filesize(fd);
  if (fsize == (uptr)-1) {
    Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
        tmp.Ptr());
    Die();
  }
  char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
  if (fsize != internal_read(fd, buf, fsize)) {
    Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
        tmp.Ptr());
    Die();
  }
  internal_close(fd);
  buf[fsize] = 0;
  return buf;
}

bool SuppressionMatch(char *templ, const char *str) {
  if (str == 0 || str[0] == 0)
    return false;
  char *tpos;
  const char *spos;
  while (templ && templ[0]) {
    if (templ[0] == '*') {
      templ++;
      continue;
    }
    if (str[0] == 0)
      return false;
    tpos = (char*)internal_strchr(templ, '*');
    if (tpos != 0)
      tpos[0] = 0;
    spos = internal_strstr(str, templ);
    str = spos + internal_strlen(templ);
    templ = tpos;
    if (tpos)
      tpos[0] = '*';
    if (spos == 0)
      return false;
  }
  return true;
}

Suppression *SuppressionParse(const char* supp) {
  Suppression *head = 0;
  const char *line = supp;
  while (line) {
    while (line[0] == ' ' || line[0] == '\t')
      line++;
    const char *end = internal_strchr(line, '\n');
    if (end == 0)
      end = line + internal_strlen(line);
    if (line != end && line[0] != '#') {
      const char *end2 = end;
      while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
        end2--;
      SuppressionType stype;
      if (0 == internal_strncmp(line, "race:", sizeof("race:") - 1)) {
        stype = SuppressionRace;
        line += sizeof("race:") - 1;
      } else if (0 == internal_strncmp(line, "thread:",
          sizeof("thread:") - 1)) {
        stype = SuppressionThread;
        line += sizeof("thread:") - 1;
      } else if (0 == internal_strncmp(line, "mutex:",
          sizeof("mutex:") - 1)) {
        stype = SuppressionMutex;
        line += sizeof("mutex:") - 1;
      } else if (0 == internal_strncmp(line, "signal:",
          sizeof("signal:") - 1)) {
        stype = SuppressionSignal;
        line += sizeof("signal:") - 1;
      } else {
        Printf("ThreadSanitizer: failed to parse suppressions file\n");
        Die();
      }
      Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
          sizeof(Suppression));
      s->next = head;
      head = s;
      s->type = stype;
      s->templ = (char*)internal_alloc(MBlockSuppression, end2 - line + 1);
      internal_memcpy(s->templ, line, end2 - line);
      s->templ[end2 - line] = 0;
    }
    if (end[0] == 0)
      break;
    line = end + 1;
  }
  return head;
}

void InitializeSuppressions() {
  char *supp = ReadFile(flags()->suppressions);
  g_suppressions = SuppressionParse(supp);
}

bool IsSuppressed(ReportType typ, const ReportStack *stack) {
  if (g_suppressions == 0 || stack == 0)
    return false;
  SuppressionType stype;
  if (typ == ReportTypeRace)
    stype = SuppressionRace;
  else if (typ == ReportTypeThreadLeak)
    stype = SuppressionThread;
  else if (typ == ReportTypeMutexDestroyLocked)
    stype = SuppressionMutex;
  else if (typ == ReportTypeSignalUnsafe)
    stype = SuppressionSignal;
  else
    return false;
  for (const ReportStack *frame = stack; frame; frame = frame->next) {
    for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
      if (stype == supp->type &&
          (SuppressionMatch(supp->templ, frame->func) ||
          SuppressionMatch(supp->templ, frame->file))) {
        DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
        return true;
      }
    }
  }
  return false;
}
}  // namespace __tsan
<|endoftext|>


<commit_before>// Copyright (c) 2013 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 "base/basictypes.h"
#include "base/command_line.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "content/shell/shell.h"
#include "content/test/content_browser_test_utils.h"
#include "content/test/layout_browsertest.h"
#include "googleurl/src/gurl.h"

// Common media types.
static const char kWebMAudioOnly[] = "audio/webm; codecs=\"vorbis\"";
static const char kWebMVideoOnly[] = "video/webm; codecs=\"vp8\"";
static const char kWebMAudioVideo[] = "video/webm; codecs=\"vorbis, vp8\"";

// Common test expectations.
const string16 kEnded = ASCIIToUTF16("ENDED");
const string16 kError = ASCIIToUTF16("ERROR");
const string16 kFailed = ASCIIToUTF16("FAILED");

namespace content {

class MediaSourceTest :  public ContentBrowserTest {
 public:
  void TestSimplePlayback(const char* media_file, const char* media_type,
                          const string16 expectation) {
    ASSERT_NO_FATAL_FAILURE(
        RunTest("media_source_player.html", media_file, media_type,
                expectation));
  }

  void RunTest(const char* html_page, const char* media_file,
               const char* media_type, const string16 expectation) {
    ASSERT_TRUE(test_server()->Start());
    GURL player_gurl = test_server()->GetURL(base::StringPrintf(
        "files/media/%s?mediafile=%s&mediatype=%s", html_page, media_file,
        media_type));
    TitleWatcher title_watcher(shell()->web_contents(), expectation);
    title_watcher.AlsoWaitForTitle(kError);
    title_watcher.AlsoWaitForTitle(kFailed);

    NavigateToURL(shell(), player_gurl);
    string16 final_title = title_watcher.WaitAndGetTitle();
    EXPECT_EQ(expectation, final_title);

    if (final_title == kFailed) {
      std::string fail_message;
      EXPECT_TRUE(ExecuteScriptAndExtractString(
          shell()->web_contents(),
          "window.domAutomationController.send(failMessage);",
          &fail_message));
      LOG(INFO) << "Test failed: " << fail_message;
    }
  }
};

IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_VideoAudio_WebM) {
  TestSimplePlayback("bear-320x240.webm", kWebMAudioVideo, kEnded);
}

IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_VideoOnly_WebM) {
  TestSimplePlayback("bear-320x240-video-only.webm", kWebMVideoOnly, kEnded);
}

IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_AudioOnly_WebM) {
  TestSimplePlayback("bear-320x240-audio-only.webm", kWebMAudioOnly, kEnded);
}

IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_Type_Error) {
  TestSimplePlayback("bear-320x240-video-only.webm", kWebMAudioOnly, kError);
}

IN_PROC_BROWSER_TEST_F(MediaSourceTest, ConfigChangeVideo) {
  ASSERT_NO_FATAL_FAILURE(
      RunTest("mse_config_change.html", NULL, NULL, kEnded));
}

}  // namespace content<commit_msg>Disable ConfigChangeVideo test.<commit_after>// Copyright (c) 2013 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 "base/basictypes.h"
#include "base/command_line.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "content/shell/shell.h"
#include "content/test/content_browser_test_utils.h"
#include "content/test/layout_browsertest.h"
#include "googleurl/src/gurl.h"

// Common media types.
static const char kWebMAudioOnly[] = "audio/webm; codecs=\"vorbis\"";
static const char kWebMVideoOnly[] = "video/webm; codecs=\"vp8\"";
static const char kWebMAudioVideo[] = "video/webm; codecs=\"vorbis, vp8\"";

// Common test expectations.
const string16 kEnded = ASCIIToUTF16("ENDED");
const string16 kError = ASCIIToUTF16("ERROR");
const string16 kFailed = ASCIIToUTF16("FAILED");

namespace content {

class MediaSourceTest :  public ContentBrowserTest {
 public:
  void TestSimplePlayback(const char* media_file, const char* media_type,
                          const string16 expectation) {
    ASSERT_NO_FATAL_FAILURE(
        RunTest("media_source_player.html", media_file, media_type,
                expectation));
  }

  void RunTest(const char* html_page, const char* media_file,
               const char* media_type, const string16 expectation) {
    ASSERT_TRUE(test_server()->Start());
    GURL player_gurl = test_server()->GetURL(base::StringPrintf(
        "files/media/%s?mediafile=%s&mediatype=%s", html_page, media_file,
        media_type));
    TitleWatcher title_watcher(shell()->web_contents(), expectation);
    title_watcher.AlsoWaitForTitle(kError);
    title_watcher.AlsoWaitForTitle(kFailed);

    NavigateToURL(shell(), player_gurl);
    string16 final_title = title_watcher.WaitAndGetTitle();
    EXPECT_EQ(expectation, final_title);

    if (final_title == kFailed) {
      std::string fail_message;
      EXPECT_TRUE(ExecuteScriptAndExtractString(
          shell()->web_contents(),
          "window.domAutomationController.send(failMessage);",
          &fail_message));
      LOG(INFO) << "Test failed: " << fail_message;
    }
  }
};

IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_VideoAudio_WebM) {
  TestSimplePlayback("bear-320x240.webm", kWebMAudioVideo, kEnded);
}

IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_VideoOnly_WebM) {
  TestSimplePlayback("bear-320x240-video-only.webm", kWebMVideoOnly, kEnded);
}

IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_AudioOnly_WebM) {
  TestSimplePlayback("bear-320x240-audio-only.webm", kWebMAudioOnly, kEnded);
}

IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_Type_Error) {
  TestSimplePlayback("bear-320x240-video-only.webm", kWebMAudioOnly, kError);
}

IN_PROC_BROWSER_TEST_F(MediaSourceTest, DISABLED_ConfigChangeVideo) {
  ASSERT_NO_FATAL_FAILURE(
      RunTest("mse_config_change.html", NULL, NULL, kEnded));
}

}  // namespace content<|endoftext|>


<commit_before><commit_msg>fixed bug when trackers are removed from torrent<commit_after><|endoftext|>


<commit_before>/*
 FILNAMN: 		NetClient.cc
 PROGRAMMERARE:	hanel742, eriek984, jened502, tobgr602, niker917, davha227
 SKAPAD DATUM:	2013-11-19
 BESKRIVNING:
 */

#include "NetClient.h"
#include "../gui/gui.h"

using namespace std;

NetClient::NetClient(QString username, QString inAddress, Gui* myGui, QObject *parent) : QObject(parent){

    guiPointer = myGui;
    name=username;
    address=inAddress;
    compare += 0x1F;
    breaker +=0x1E;
}

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

void NetClient::start(){
    TcpSocket = new QTcpSocket(this);

    connect(TcpSocket,SIGNAL(connected()),this,SLOT(connected()));
    connect(TcpSocket,SIGNAL(disconnected()),this,SLOT(disconnected()));
    connect(TcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead()));

    QHostInfo info = QHostInfo::fromName(address);

    if (info.addresses().size() == 0){
        guiPointer->noConnection();
    }
    else{
        TcpSocket->connectToHost(info.addresses().at(0),quint16(40001));
        if(!TcpSocket->waitForConnected(1000)){
            guiPointer->noConnection();
        }
    }
}

//------Slots---------

void NetClient::connected(){
    QByteArray array = "/initiate";
    array += 0x1F; //unit separator
    array += name;
    array += breaker;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}

void NetClient::disconnected(){
    guiPointer->disconnectedFromServer();

}

// --------readyRead------------------

void NetClient::readyRead(){

    QString inData = "";

    if( not(incompleteCommand.isEmpty())){
        inData = incompleteCommand;
        cout << "old command exists" << endl;
        incompleteCommand = "";
    }
    QByteArray Data = TcpSocket->readAll();

    QString commandName = "";
    inData += Data;
    QString rest = "";
    int n = inData.indexOf(breaker);
    int i;
    int p = 0;

    if(inData.indexOf(breaker) == -1 ){
        cout << "breaker missing " << endl;
        incompleteCommand = inData;
        return;
    }

    do {

        rest = inData.mid(n+1);
        inData = inData.left(n);
        i = inData.indexOf(compare);
        cout << p << endl;
        commandName = inData.left(i);

        p = p + 1;
        inData = inData.mid(i+1);

        QString temp = inData;
        string stdInData = temp.toStdString();

        // Check which command that's supposed to run
        if (commandName == "/reinitiate") {
            guiPointer->userNameTaken();
            break;
        }

        else if ( commandName == "/userAccepted") {
            guiPointer->connected();
        }

        else if (commandName == "/history") {
            handleHistory(inData);
        }

        else if (commandName == "/oldHistory") {
            handleOldHistory(inData);
        }

        else if (commandName == "/message") {
            handleMessage(inData);
        }

        else if ( commandName == "/requestStruct") {
            handleRequestStruct();
        }

        else if ( commandName == "/structure" ) {
            handleStructure(inData);
        }

        else {

            throw logic_error("Unknown command: " + commandName.toStdString());
        }

        inData = rest;
        n = inData.indexOf(breaker);
        commandName = "";

    }while (n != -1 );
}

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

void NetClient::sendMessage(QString from, QString to, QString message){
    QByteArray array = "/message";
    array += 0x1F; //unit separator
    array += from;
    array += 0x1F;
    array += to;
    array += 0x1F;
    array += message;
    array += breaker;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}

void NetClient::setName(QString inName) {
    name=inName;
}

void NetClient::getStruct(){
    QByteArray array = "/structure";
    array += 0x1E;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}

//--------------------------------------------
//Helpfunctions

void NetClient::handleRequestStruct(){
    QByteArray array = "/structure";
    array += compare;
    array += breaker;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}

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

void NetClient::handleMessage(QString inData){

    int i;
    // Get from
    i = inData.indexOf(compare);
    QString from = inData.left(i);
    inData = inData.mid(i+1);

    // Get to
    i = inData.indexOf(compare);
    QString to = inData.left(i);
    inData = inData.mid(i+1);

    // Get message
    i = inData.indexOf(compare);
    QString contents = inData.left(i);
    inData = inData.mid(i+1);

    // Get time
    QString dateTime = inData;

    //Send message to Gui
    guiPointer->receiveMessage(from, to, contents, dateTime);

}

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

void NetClient::handleHistory(QString inData){
    QVector<QString> history;
    int i = inData.indexOf(compare);
    while(i != -1 ){

        // Get from
        i = inData.indexOf(compare);
        QString from = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(from);

        // Get to
        i = inData.indexOf(compare);
        QString to = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(to);

        // Get message
        i = inData.indexOf(compare);
        QString contents = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(contents);

        //Get time
        i = inData.indexOf(compare);
        QString time = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(time);
    }
    guiPointer->receiveHistory(history);
}

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

void NetClient::handleOldHistory(QString inData){
    QVector<QString> history;
    int i = inData.indexOf(compare);
    while(i != -1 ){

        // Get from
        i = inData.indexOf(compare);
        QString from = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(from);

        // Get to
        i = inData.indexOf(compare);
        QString to = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(to);

        // Get message
        i = inData.indexOf(compare);
        QString contents = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(contents);

        //Get time
        i = inData.indexOf(compare);
        QString time = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(time);
    }
    guiPointer->receiveOldHistory(history);
}

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

void NetClient::handleStructure(QString inData){
    QVector<QString> output;
    int i = inData.indexOf(compare);

    while(i  != -1){
        //Create vector output, containing room content structure
        QString data = inData.left(i);
        inData = inData.mid(i+1);
        output.push_back(data);

        i = inData.indexOf(compare);
    }

    output.push_back(inData);

    guiPointer->updateStruct(output);

}

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

void NetClient::getHistory(unsigned int daysBack) {
    QString temp;
    string daysBackString = to_string(daysBack);

    temp = QString::fromStdString(daysBackString);

    QByteArray array = "/oldHistory";
    array += compare; //unit separator
    array += temp;
    array += breaker;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}

<commit_msg>NetClient non-crash on unknown commands for release version<commit_after>/*
 FILNAMN: 		NetClient.cc
 PROGRAMMERARE:	hanel742, eriek984, jened502, tobgr602, niker917, davha227
 SKAPAD DATUM:	2013-11-19
 BESKRIVNING:
 */

#include "NetClient.h"
#include "../gui/gui.h"

using namespace std;

NetClient::NetClient(QString username, QString inAddress, Gui* myGui, QObject *parent) : QObject(parent){

    guiPointer = myGui;
    name=username;
    address=inAddress;
    compare += 0x1F;
    breaker +=0x1E;
}

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

void NetClient::start(){
    TcpSocket = new QTcpSocket(this);

    connect(TcpSocket,SIGNAL(connected()),this,SLOT(connected()));
    connect(TcpSocket,SIGNAL(disconnected()),this,SLOT(disconnected()));
    connect(TcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead()));

    QHostInfo info = QHostInfo::fromName(address);

    if (info.addresses().size() == 0){
        guiPointer->noConnection();
    }
    else{
        TcpSocket->connectToHost(info.addresses().at(0),quint16(40001));
        if(!TcpSocket->waitForConnected(1000)){
            guiPointer->noConnection();
        }
    }
}

//------Slots---------

void NetClient::connected(){
    QByteArray array = "/initiate";
    array += 0x1F; //unit separator
    array += name;
    array += breaker;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}

void NetClient::disconnected(){
    guiPointer->disconnectedFromServer();

}

// --------readyRead------------------

void NetClient::readyRead(){

    QString inData = "";

    if( not(incompleteCommand.isEmpty())){
        inData = incompleteCommand;
        cout << "old command exists" << endl;
        incompleteCommand = "";
    }
    QByteArray Data = TcpSocket->readAll();

    QString commandName = "";
    inData += Data;
    QString rest = "";
    int n = inData.indexOf(breaker);
    int i;
    int p = 0;

    if(inData.indexOf(breaker) == -1 ){
        cout << "breaker missing " << endl;
        incompleteCommand = inData;
        return;
    }

    do {

        rest = inData.mid(n+1);
        inData = inData.left(n);
        i = inData.indexOf(compare);
        cout << p << endl;
        commandName = inData.left(i);

        p = p + 1;
        inData = inData.mid(i+1);

        QString temp = inData;
        string stdInData = temp.toStdString();

        // Check which command that's supposed to run
        if (commandName == "/reinitiate") {
            guiPointer->userNameTaken();
            break;
        }

        else if ( commandName == "/userAccepted") {
            guiPointer->connected();
        }

        else if (commandName == "/history") {
            handleHistory(inData);
        }

        else if (commandName == "/oldHistory") {
            handleOldHistory(inData);
        }

        else if (commandName == "/message") {
            handleMessage(inData);
        }

        else if ( commandName == "/requestStruct") {
            handleRequestStruct();
        }

        else if ( commandName == "/structure" ) {
            handleStructure(inData);
        }

        else {

            //throw logic_error("Unknown command: " + commandName.toStdString());
            //release version
            cout << "Unknown command: " << endl;
            inData = "";
            commandName = "";
            incompleteCommand = "";
            return;
        }

        inData = rest;
        n = inData.indexOf(breaker);
        commandName = "";

    }while (n != -1 );
}

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

void NetClient::sendMessage(QString from, QString to, QString message){
    QByteArray array = "/message";
    array += 0x1F; //unit separator
    array += from;
    array += 0x1F;
    array += to;
    array += 0x1F;
    array += message;
    array += breaker;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}

void NetClient::setName(QString inName) {
    name=inName;
}

void NetClient::getStruct(){
    QByteArray array = "/structure";
    array += 0x1E;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}

//--------------------------------------------
//Helpfunctions

void NetClient::handleRequestStruct(){
    QByteArray array = "/structure";
    array += compare;
    array += breaker;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}

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

void NetClient::handleMessage(QString inData){

    int i;
    // Get from
    i = inData.indexOf(compare);
    QString from = inData.left(i);
    inData = inData.mid(i+1);

    // Get to
    i = inData.indexOf(compare);
    QString to = inData.left(i);
    inData = inData.mid(i+1);

    // Get message
    i = inData.indexOf(compare);
    QString contents = inData.left(i);
    inData = inData.mid(i+1);

    // Get time
    QString dateTime = inData;

    //Send message to Gui
    guiPointer->receiveMessage(from, to, contents, dateTime);

}

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

void NetClient::handleHistory(QString inData){
    QVector<QString> history;
    int i = inData.indexOf(compare);
    while(i != -1 ){

        // Get from
        i = inData.indexOf(compare);
        QString from = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(from);

        // Get to
        i = inData.indexOf(compare);
        QString to = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(to);

        // Get message
        i = inData.indexOf(compare);
        QString contents = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(contents);

        //Get time
        i = inData.indexOf(compare);
        QString time = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(time);
    }
    guiPointer->receiveHistory(history);
}

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

void NetClient::handleOldHistory(QString inData){
    QVector<QString> history;
    int i = inData.indexOf(compare);
    while(i != -1 ){

        // Get from
        i = inData.indexOf(compare);
        QString from = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(from);

        // Get to
        i = inData.indexOf(compare);
        QString to = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(to);

        // Get message
        i = inData.indexOf(compare);
        QString contents = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(contents);

        //Get time
        i = inData.indexOf(compare);
        QString time = inData.left(i);
        inData = inData.mid(i+1);
        history.push_back(time);
    }
    guiPointer->receiveOldHistory(history);
}

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

void NetClient::handleStructure(QString inData){
    QVector<QString> output;
    int i = inData.indexOf(compare);

    while(i  != -1){
        //Create vector output, containing room content structure
        QString data = inData.left(i);
        inData = inData.mid(i+1);
        output.push_back(data);

        i = inData.indexOf(compare);
    }

    output.push_back(inData);

    guiPointer->updateStruct(output);

}

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

void NetClient::getHistory(unsigned int daysBack) {
    QString temp;
    string daysBackString = to_string(daysBack);

    temp = QString::fromStdString(daysBackString);

    QByteArray array = "/oldHistory";
    array += compare; //unit separator
    array += temp;
    array += breaker;

    TcpSocket->write(array);
    TcpSocket->waitForBytesWritten(1000);
}

<|endoftext|>


<commit_before>#include "shell_manager.hh"

#include "buffer_utils.hh"
#include "clock.hh"
#include "context.hh"
#include "display_buffer.hh"
#include "event_manager.hh"
#include "face_registry.hh"
#include "file.hh"
#include "regex.hh"

#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>

extern char **environ;

namespace Kakoune
{

ShellManager::ShellManager()
{
    // Get a guaranteed to be POSIX shell binary
    {
        auto size = confstr(_CS_PATH, 0, 0);
        String path; path.resize(size, 0);
        confstr(_CS_PATH, path.data(), size);
        for (auto dir : StringView{path} | split<StringView>(':'))
        {
            String candidate = format("{}/sh", dir);
            struct stat st;
            if (stat(candidate.c_str(), &st))
                continue;

            bool executable = (st.st_mode & S_IXUSR)
                            | (st.st_mode & S_IXGRP)
                            | (st.st_mode & S_IXOTH);
            if (S_ISREG(st.st_mode) and executable)
            {
                m_shell = std::move(candidate);
                break;
            }
        }
        if (m_shell.empty())
            throw runtime_error{format("unable to find a posix shell in {}", path)};
    }

    // Add Kakoune binary location to the path to guarantee that %sh{ ... }
    // have access to the kak command regardless of if the user installed it
    {
        const char* path = getenv("PATH");
        auto new_path = format("{}:{}", path, split_path(get_kak_binary_path()).first);
        setenv("PATH", new_path.c_str(), 1);
    }
}

namespace
{

struct Pipe
{
    Pipe(bool create = true)
        : m_fd{-1, -1}
    {
        if (create and ::pipe(m_fd) < 0)
            throw runtime_error(format("unable to create pipe (fds: {}/{}; errno: {})", m_fd[0], m_fd[1], ::strerror(errno)));
    }
    ~Pipe() { close_read_fd(); close_write_fd(); }

    int read_fd() const { return m_fd[0]; }
    int write_fd() const { return m_fd[1]; }

    void close_read_fd() { close_fd(m_fd[0]); }
    void close_write_fd() { close_fd(m_fd[1]); }

private:
    void close_fd(int& fd) { if (fd != -1) { close(fd); fd = -1; } }
    int m_fd[2];
};

template<typename Func>
pid_t spawn_shell(const char* shell, StringView cmdline,
                  ConstArrayView<String> params,
                  ConstArrayView<String> kak_env,
                  Func setup_child)
{
    Vector<const char*> envptrs;
    for (char** envp = environ; *envp; ++envp)
        envptrs.push_back(*envp);
    for (auto& env : kak_env)
        envptrs.push_back(env.c_str());
    envptrs.push_back(nullptr);

    auto cmdlinezstr = cmdline.zstr();
    Vector<const char*> execparams = { shell, "-c", cmdlinezstr };
    if (not params.empty())
        execparams.push_back(shell);
    for (auto& param : params)
        execparams.push_back(param.c_str());
    execparams.push_back(nullptr);

    if (pid_t pid = fork())
        return pid;

    setup_child();

    execve(shell, (char* const*)execparams.data(), (char* const*)envptrs.data());
    exit(-1);
    return -1;
}

Vector<String> generate_env(StringView cmdline, const Context& context, const ShellContext& shell_context)
{
    static const Regex re(R"(\bkak_(\w+)\b)");

    Vector<String> kak_env;
    for (RegexIterator<const char*> it{cmdline.begin(), cmdline.end(), re}, end;
         it != end; ++it)
    {
        StringView name{(*it)[1].first, (*it)[1].second};

        auto match_name = [&](const String& s) {
            return s.length() > name.length()  and
                   prefix_match(s, name) and s[name.length()] == '=';
        };
        if (contains_that(kak_env, match_name))
            continue;

        auto var_it = shell_context.env_vars.find(name);
        try
        {
            const String& value = var_it != shell_context.env_vars.end() ?
                var_it->value : ShellManager::instance().get_val(name, context);

            kak_env.push_back(format("kak_{}={}", name, value));
        } catch (runtime_error&) {}
    }

    return kak_env;
}

}

std::pair<String, int> ShellManager::eval(
    StringView cmdline, const Context& context, StringView input,
    Flags flags, const ShellContext& shell_context)
{
    const DebugFlags debug_flags = context.options()["debug"].get<DebugFlags>();
    const bool profile = debug_flags & DebugFlags::Profile;
    if (debug_flags & DebugFlags::Shell)
        write_to_debug_buffer(format("shell:\n{}\n----\n", cmdline));

    auto start_time = profile ? Clock::now() : Clock::time_point{};

    auto kak_env = generate_env(cmdline, context, shell_context);

    auto spawn_time = profile ? Clock::now() : Clock::time_point{};

    Pipe child_stdin{not input.empty()}, child_stdout, child_stderr;
    pid_t pid = spawn_shell(m_shell.c_str(), cmdline, shell_context.params, kak_env,
                            [&child_stdin, &child_stdout, &child_stderr] {
        auto move = [](int oldfd, int newfd) { dup2(oldfd, newfd); close(oldfd); };

        if (child_stdin.read_fd() != -1)
        {
            close(child_stdin.write_fd());
            move(child_stdin.read_fd(), 0);
        }

        close(child_stdout.read_fd());
        move(child_stdout.write_fd(), 1);

        close(child_stderr.read_fd());
        move(child_stderr.write_fd(), 2);
    });

    child_stdin.close_read_fd();
    child_stdout.close_write_fd();
    child_stderr.close_write_fd();

    write(child_stdin.write_fd(), input);
    child_stdin.close_write_fd();

    auto wait_time = Clock::now();

    struct PipeReader : FDWatcher
    {
        PipeReader(Pipe& pipe, String& contents)
            : FDWatcher(pipe.read_fd(), FdEvents::Read,
                        [&contents, &pipe](FDWatcher& watcher, FdEvents, EventMode) {
                            char buffer[1024];
                            while (fd_readable(pipe.read_fd()))
                            {
                                size_t size = ::read(pipe.read_fd(), buffer, 1024);
                                if (size <= 0)
                                {
                                    pipe.close_read_fd();
                                    watcher.disable();
                                    return;
                                }
                                contents += StringView{buffer, buffer+size};
                            }
                        })
        {}
    };

    String stdout_contents, stderr_contents;
    PipeReader stdout_reader{child_stdout, stdout_contents};
    PipeReader stderr_reader{child_stderr, stderr_contents};

    // block SIGCHLD to make sure we wont receive it before
    // our call to pselect, that will end up blocking indefinitly.
    sigset_t mask, orig_mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGCHLD);
    sigprocmask(SIG_BLOCK, &mask, &orig_mask);
    auto restore_mask = on_scope_end([&] { sigprocmask(SIG_SETMASK, &orig_mask, nullptr); });

    int status = 0;
    // check for termination now that SIGCHLD is blocked
    bool terminated = waitpid(pid, &status, WNOHANG);

    using namespace std::chrono;
    static constexpr seconds wait_timeout{1};
    bool wait_notified = false;
    Timer wait_timer{wait_time + wait_timeout, [&](Timer& timer)
    {
        auto wait_duration = Clock::now() - wait_time;
        context.print_status({ format("waiting for shell command to finish ({}s)",
                                      duration_cast<seconds>(wait_duration).count()),
                                get_face("Information") }, true);
        timer.set_next_date(Clock::now() + wait_timeout);
        wait_notified = true;
    }, EventMode::Urgent};

    while (not terminated or
           ((flags & Flags::WaitForStdout) and
            (child_stdout.read_fd() != -1 or child_stderr.read_fd() != -1)))
    {
        EventManager::instance().handle_next_events(EventMode::Urgent, &orig_mask);
        if (not terminated)
            terminated = waitpid(pid, &status, WNOHANG);
    }

    if (not stderr_contents.empty())
        write_to_debug_buffer(format("shell stderr: <<<\n{}>>>", stderr_contents));

    if (profile)
    {
        auto end_time = Clock::now();
        auto full = duration_cast<milliseconds>(end_time - start_time);
        auto spawn = duration_cast<milliseconds>(wait_time - spawn_time);
        auto wait = duration_cast<milliseconds>(end_time - wait_time);
        write_to_debug_buffer(format("shell execution took {} ms (spawn: {}, wait: {})",
                                     (size_t)full.count(), (size_t)spawn.count(), (size_t)wait.count()));
    }

    if (wait_notified) // clear the status line
        context.print_status({ "", get_face("Information") }, true);

    return { std::move(stdout_contents), WIFEXITED(status) ? WEXITSTATUS(status) : -1 };
}

void ShellManager::register_env_var(StringView str, bool prefix,
                                    EnvVarRetriever retriever)
{
    m_env_vars.push_back({ str.str(), prefix, std::move(retriever) });
}

String ShellManager::get_val(StringView name, const Context& context) const
{
    auto env_var = std::find_if(
        m_env_vars.begin(), m_env_vars.end(),
        [name](const EnvVarDesc& desc) {
            return desc.prefix ? prefix_match(name, desc.str) : name == desc.str;
        });

    if (env_var == m_env_vars.end())
        throw runtime_error("no such env var: " + name);

    return env_var->func(name, context);
}

CandidateList ShellManager::complete_env_var(StringView prefix,
                                             ByteCount cursor_pos) const
{
    return complete(prefix, cursor_pos,
                    m_env_vars | transform(std::mem_fn(&EnvVarDesc::str)));
}

}
<commit_msg>Fix getting path confstr, the returned size includes the zero terminator<commit_after>#include "shell_manager.hh"

#include "buffer_utils.hh"
#include "clock.hh"
#include "context.hh"
#include "display_buffer.hh"
#include "event_manager.hh"
#include "face_registry.hh"
#include "file.hh"
#include "regex.hh"

#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>

extern char **environ;

namespace Kakoune
{

ShellManager::ShellManager()
{
    // Get a guaranteed to be POSIX shell binary
    {
        auto size = confstr(_CS_PATH, 0, 0);
        String path; path.resize(size-1, 0);
        confstr(_CS_PATH, path.data(), size);
        for (auto dir : StringView{path} | split<StringView>(':'))
        {
            String candidate = format("{}/sh", dir);
            struct stat st;
            if (stat(candidate.c_str(), &st))
                continue;

            bool executable = (st.st_mode & S_IXUSR)
                            | (st.st_mode & S_IXGRP)
                            | (st.st_mode & S_IXOTH);
            if (S_ISREG(st.st_mode) and executable)
            {
                m_shell = std::move(candidate);
                break;
            }
        }
        if (m_shell.empty())
            throw runtime_error{format("unable to find a posix shell in {}", path)};
    }

    // Add Kakoune binary location to the path to guarantee that %sh{ ... }
    // have access to the kak command regardless of if the user installed it
    {
        const char* path = getenv("PATH");
        auto new_path = format("{}:{}", path, split_path(get_kak_binary_path()).first);
        setenv("PATH", new_path.c_str(), 1);
    }
}

namespace
{

struct Pipe
{
    Pipe(bool create = true)
        : m_fd{-1, -1}
    {
        if (create and ::pipe(m_fd) < 0)
            throw runtime_error(format("unable to create pipe (fds: {}/{}; errno: {})", m_fd[0], m_fd[1], ::strerror(errno)));
    }
    ~Pipe() { close_read_fd(); close_write_fd(); }

    int read_fd() const { return m_fd[0]; }
    int write_fd() const { return m_fd[1]; }

    void close_read_fd() { close_fd(m_fd[0]); }
    void close_write_fd() { close_fd(m_fd[1]); }

private:
    void close_fd(int& fd) { if (fd != -1) { close(fd); fd = -1; } }
    int m_fd[2];
};

template<typename Func>
pid_t spawn_shell(const char* shell, StringView cmdline,
                  ConstArrayView<String> params,
                  ConstArrayView<String> kak_env,
                  Func setup_child)
{
    Vector<const char*> envptrs;
    for (char** envp = environ; *envp; ++envp)
        envptrs.push_back(*envp);
    for (auto& env : kak_env)
        envptrs.push_back(env.c_str());
    envptrs.push_back(nullptr);

    auto cmdlinezstr = cmdline.zstr();
    Vector<const char*> execparams = { shell, "-c", cmdlinezstr };
    if (not params.empty())
        execparams.push_back(shell);
    for (auto& param : params)
        execparams.push_back(param.c_str());
    execparams.push_back(nullptr);

    if (pid_t pid = fork())
        return pid;

    setup_child();

    execve(shell, (char* const*)execparams.data(), (char* const*)envptrs.data());
    exit(-1);
    return -1;
}

Vector<String> generate_env(StringView cmdline, const Context& context, const ShellContext& shell_context)
{
    static const Regex re(R"(\bkak_(\w+)\b)");

    Vector<String> kak_env;
    for (RegexIterator<const char*> it{cmdline.begin(), cmdline.end(), re}, end;
         it != end; ++it)
    {
        StringView name{(*it)[1].first, (*it)[1].second};

        auto match_name = [&](const String& s) {
            return s.length() > name.length()  and
                   prefix_match(s, name) and s[name.length()] == '=';
        };
        if (contains_that(kak_env, match_name))
            continue;

        auto var_it = shell_context.env_vars.find(name);
        try
        {
            const String& value = var_it != shell_context.env_vars.end() ?
                var_it->value : ShellManager::instance().get_val(name, context);

            kak_env.push_back(format("kak_{}={}", name, value));
        } catch (runtime_error&) {}
    }

    return kak_env;
}

}

std::pair<String, int> ShellManager::eval(
    StringView cmdline, const Context& context, StringView input,
    Flags flags, const ShellContext& shell_context)
{
    const DebugFlags debug_flags = context.options()["debug"].get<DebugFlags>();
    const bool profile = debug_flags & DebugFlags::Profile;
    if (debug_flags & DebugFlags::Shell)
        write_to_debug_buffer(format("shell:\n{}\n----\n", cmdline));

    auto start_time = profile ? Clock::now() : Clock::time_point{};

    auto kak_env = generate_env(cmdline, context, shell_context);

    auto spawn_time = profile ? Clock::now() : Clock::time_point{};

    Pipe child_stdin{not input.empty()}, child_stdout, child_stderr;
    pid_t pid = spawn_shell(m_shell.c_str(), cmdline, shell_context.params, kak_env,
                            [&child_stdin, &child_stdout, &child_stderr] {
        auto move = [](int oldfd, int newfd) { dup2(oldfd, newfd); close(oldfd); };

        if (child_stdin.read_fd() != -1)
        {
            close(child_stdin.write_fd());
            move(child_stdin.read_fd(), 0);
        }

        close(child_stdout.read_fd());
        move(child_stdout.write_fd(), 1);

        close(child_stderr.read_fd());
        move(child_stderr.write_fd(), 2);
    });

    child_stdin.close_read_fd();
    child_stdout.close_write_fd();
    child_stderr.close_write_fd();

    write(child_stdin.write_fd(), input);
    child_stdin.close_write_fd();

    auto wait_time = Clock::now();

    struct PipeReader : FDWatcher
    {
        PipeReader(Pipe& pipe, String& contents)
            : FDWatcher(pipe.read_fd(), FdEvents::Read,
                        [&contents, &pipe](FDWatcher& watcher, FdEvents, EventMode) {
                            char buffer[1024];
                            while (fd_readable(pipe.read_fd()))
                            {
                                size_t size = ::read(pipe.read_fd(), buffer, 1024);
                                if (size <= 0)
                                {
                                    pipe.close_read_fd();
                                    watcher.disable();
                                    return;
                                }
                                contents += StringView{buffer, buffer+size};
                            }
                        })
        {}
    };

    String stdout_contents, stderr_contents;
    PipeReader stdout_reader{child_stdout, stdout_contents};
    PipeReader stderr_reader{child_stderr, stderr_contents};

    // block SIGCHLD to make sure we wont receive it before
    // our call to pselect, that will end up blocking indefinitly.
    sigset_t mask, orig_mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGCHLD);
    sigprocmask(SIG_BLOCK, &mask, &orig_mask);
    auto restore_mask = on_scope_end([&] { sigprocmask(SIG_SETMASK, &orig_mask, nullptr); });

    int status = 0;
    // check for termination now that SIGCHLD is blocked
    bool terminated = waitpid(pid, &status, WNOHANG);

    using namespace std::chrono;
    static constexpr seconds wait_timeout{1};
    bool wait_notified = false;
    Timer wait_timer{wait_time + wait_timeout, [&](Timer& timer)
    {
        auto wait_duration = Clock::now() - wait_time;
        context.print_status({ format("waiting for shell command to finish ({}s)",
                                      duration_cast<seconds>(wait_duration).count()),
                                get_face("Information") }, true);
        timer.set_next_date(Clock::now() + wait_timeout);
        wait_notified = true;
    }, EventMode::Urgent};

    while (not terminated or
           ((flags & Flags::WaitForStdout) and
            (child_stdout.read_fd() != -1 or child_stderr.read_fd() != -1)))
    {
        EventManager::instance().handle_next_events(EventMode::Urgent, &orig_mask);
        if (not terminated)
            terminated = waitpid(pid, &status, WNOHANG);
    }

    if (not stderr_contents.empty())
        write_to_debug_buffer(format("shell stderr: <<<\n{}>>>", stderr_contents));

    if (profile)
    {
        auto end_time = Clock::now();
        auto full = duration_cast<milliseconds>(end_time - start_time);
        auto spawn = duration_cast<milliseconds>(wait_time - spawn_time);
        auto wait = duration_cast<milliseconds>(end_time - wait_time);
        write_to_debug_buffer(format("shell execution took {} ms (spawn: {}, wait: {})",
                                     (size_t)full.count(), (size_t)spawn.count(), (size_t)wait.count()));
    }

    if (wait_notified) // clear the status line
        context.print_status({ "", get_face("Information") }, true);

    return { std::move(stdout_contents), WIFEXITED(status) ? WEXITSTATUS(status) : -1 };
}

void ShellManager::register_env_var(StringView str, bool prefix,
                                    EnvVarRetriever retriever)
{
    m_env_vars.push_back({ str.str(), prefix, std::move(retriever) });
}

String ShellManager::get_val(StringView name, const Context& context) const
{
    auto env_var = std::find_if(
        m_env_vars.begin(), m_env_vars.end(),
        [name](const EnvVarDesc& desc) {
            return desc.prefix ? prefix_match(name, desc.str) : name == desc.str;
        });

    if (env_var == m_env_vars.end())
        throw runtime_error("no such env var: " + name);

    return env_var->func(name, context);
}

CandidateList ShellManager::complete_env_var(StringView prefix,
                                             ByteCount cursor_pos) const
{
    return complete(prefix, cursor_pos,
                    m_env_vars | transform(std::mem_fn(&EnvVarDesc::str)));
}

}
<|endoftext|>