<commit_before>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Andreas Hansson
 */

#include "mem/addr_mapper.hh"

AddrMapper::AddrMapper(const AddrMapperParams* p)
    : MemObject(p),
      masterPort(name() + "-master", *this),
      slavePort(name() + "-slave", *this)
{
}

void
AddrMapper::init()
{
    if (!slavePort.isConnected() || !masterPort.isConnected())
        fatal("Address mapper is not connected on both sides.\n");

    if ((slavePort.peerBlockSize() != masterPort.peerBlockSize()) &&
        slavePort.peerBlockSize() && masterPort.peerBlockSize())
        fatal("Slave port size %d, master port size %d \n "
              "don't have the same block size... Not supported.\n",
              slavePort.peerBlockSize(), masterPort.peerBlockSize());
}

BaseMasterPort&
AddrMapper::getMasterPort(const std::string& if_name, PortID idx)
{
    if (if_name == "master") {
        return masterPort;
    } else {
        return MemObject::getMasterPort(if_name, idx);
    }
}

BaseSlavePort&
AddrMapper::getSlavePort(const std::string& if_name, PortID idx)
{
    if (if_name == "slave") {
        return slavePort;
    } else {
        return MemObject::getSlavePort(if_name, idx);
    }
}

void
AddrMapper::recvFunctional(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    masterPort.sendFunctional(pkt);
    pkt->setAddr(orig_addr);
}

void
AddrMapper::recvFunctionalSnoop(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    slavePort.sendFunctionalSnoop(pkt);
    pkt->setAddr(orig_addr);
}

Tick
AddrMapper::recvAtomic(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    Tick ret_tick =  masterPort.sendAtomic(pkt);
    pkt->setAddr(orig_addr);
    return ret_tick;
}

Tick
AddrMapper::recvAtomicSnoop(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    Tick ret_tick = slavePort.sendAtomicSnoop(pkt);
    pkt->setAddr(orig_addr);
    return ret_tick;
}

bool
AddrMapper::recvTimingReq(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    bool needsResponse = pkt->needsResponse();
    bool memInhibitAsserted = pkt->memInhibitAsserted();
    Packet::SenderState* senderState = pkt->senderState;

    if (needsResponse && !memInhibitAsserted) {
        pkt->senderState = new AddrMapperSenderState(senderState, orig_addr);
    }

    pkt->setAddr(remapAddr(orig_addr));

    // Attempt to send the packet (always succeeds for inhibited
    // packets)
    bool successful = masterPort.sendTimingReq(pkt);

    // If not successful, restore the sender state
    if (!successful && needsResponse) {
        delete pkt->senderState;
        pkt->senderState = senderState;
    }

    return successful;
}

bool
AddrMapper::recvTimingResp(PacketPtr pkt)
{
    AddrMapperSenderState* receivedState =
        dynamic_cast<AddrMapperSenderState*>(pkt->senderState);

    // Restore initial sender state
    if (receivedState == NULL)
        panic("AddrMapper %s got a response without sender state\n",
              name());

    Addr remapped_addr = pkt->getAddr();

    // Restore the state and address
    pkt->senderState = receivedState->origSenderState;
    pkt->setAddr(receivedState->origAddr);

    // Attempt to send the packet
    bool successful = slavePort.sendTimingResp(pkt);

    // If packet successfully sent, delete the sender state, otherwise
    // restore state
    if (successful) {
        delete receivedState;
    } else {
        // Don't delete anything and let the packet look like we did
        // not touch it
        pkt->senderState = receivedState;
        pkt->setAddr(remapped_addr);
    }
    return successful;
}

void
AddrMapper::recvTimingSnoopReq(PacketPtr pkt)
{
    slavePort.sendTimingSnoopReq(pkt);
}

bool
AddrMapper::recvTimingSnoopResp(PacketPtr pkt)
{
    return masterPort.sendTimingSnoopResp(pkt);
}

bool
AddrMapper::isSnooping() const
{
    if (slavePort.isSnooping())
        fatal("AddrMapper doesn't support remapping of snooping requests\n");
    return false;
}

unsigned
AddrMapper::deviceBlockSizeMaster()
{
    return slavePort.peerBlockSize();
}

unsigned
AddrMapper::deviceBlockSizeSlave()
{
    return masterPort.peerBlockSize();
}

void
AddrMapper::recvRetryMaster()
{
    slavePort.sendRetry();
}

void
AddrMapper::recvRetrySlave()
{
    masterPort.sendRetry();
}

void
AddrMapper::recvRangeChange()
{
    slavePort.sendRangeChange();
}

RangeAddrMapper::RangeAddrMapper(const RangeAddrMapperParams* p) :
    AddrMapper(p),
    originalRanges(p->original_ranges),
    remappedRanges(p->remapped_ranges)
{
    if (originalRanges.size() != remappedRanges.size())
        fatal("AddrMapper: original and shadowed range list must "
              "be same size\n");

    for (size_t x = 0; x < originalRanges.size(); x++) {
        if (originalRanges[x].size() != remappedRanges[x].size())
            fatal("AddrMapper: original and shadowed range list elements"
                  " aren't all of the same size\n");
    }
}

RangeAddrMapper*
RangeAddrMapperParams::create()
{
    return new RangeAddrMapper(this);
}

Addr
RangeAddrMapper::remapAddr(Addr addr) const
{
    for (int i = 0; i < originalRanges.size(); ++i) {
        if (originalRanges[i].contains(addr)) {
            Addr offset = addr - originalRanges[i].start();
            return offset + remappedRanges[i].start();
        }
    }

    return addr;
}

AddrRangeList
RangeAddrMapper::getAddrRanges() const
{
    AddrRangeList ranges;
    AddrRangeList actualRanges = masterPort.getAddrRanges();

    for (AddrRangeIter r = actualRanges.begin(); r != actualRanges.end(); ++r) {
        AddrRange range = *r;

        for (int j = 0; j < originalRanges.size(); ++j) {
            if (range.intersects(originalRanges[j]))
                fatal("Cannot remap range that intersects the original"
                      " ranges but are not a subset.\n");
            if (range.isSubset(originalRanges[j])) {
                // range is a subset
                Addr offset = range.start() - originalRanges[j].start();
                Addr start = range.start() - offset;
                ranges.push_back(AddrRange(start, start + range.size() - 1));
            } else {
                ranges.push_back(range);
            }
        }
    }

    return ranges;
}

<commit_msg>mem: Skip address mapper range checks to allow more flexibility<commit_after>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Andreas Hansson
 */

#include "mem/addr_mapper.hh"

AddrMapper::AddrMapper(const AddrMapperParams* p)
    : MemObject(p),
      masterPort(name() + "-master", *this),
      slavePort(name() + "-slave", *this)
{
}

void
AddrMapper::init()
{
    if (!slavePort.isConnected() || !masterPort.isConnected())
        fatal("Address mapper is not connected on both sides.\n");

    if ((slavePort.peerBlockSize() != masterPort.peerBlockSize()) &&
        slavePort.peerBlockSize() && masterPort.peerBlockSize())
        fatal("Slave port size %d, master port size %d \n "
              "don't have the same block size... Not supported.\n",
              slavePort.peerBlockSize(), masterPort.peerBlockSize());
}

BaseMasterPort&
AddrMapper::getMasterPort(const std::string& if_name, PortID idx)
{
    if (if_name == "master") {
        return masterPort;
    } else {
        return MemObject::getMasterPort(if_name, idx);
    }
}

BaseSlavePort&
AddrMapper::getSlavePort(const std::string& if_name, PortID idx)
{
    if (if_name == "slave") {
        return slavePort;
    } else {
        return MemObject::getSlavePort(if_name, idx);
    }
}

void
AddrMapper::recvFunctional(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    masterPort.sendFunctional(pkt);
    pkt->setAddr(orig_addr);
}

void
AddrMapper::recvFunctionalSnoop(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    slavePort.sendFunctionalSnoop(pkt);
    pkt->setAddr(orig_addr);
}

Tick
AddrMapper::recvAtomic(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    Tick ret_tick =  masterPort.sendAtomic(pkt);
    pkt->setAddr(orig_addr);
    return ret_tick;
}

Tick
AddrMapper::recvAtomicSnoop(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    Tick ret_tick = slavePort.sendAtomicSnoop(pkt);
    pkt->setAddr(orig_addr);
    return ret_tick;
}

bool
AddrMapper::recvTimingReq(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    bool needsResponse = pkt->needsResponse();
    bool memInhibitAsserted = pkt->memInhibitAsserted();
    Packet::SenderState* senderState = pkt->senderState;

    if (needsResponse && !memInhibitAsserted) {
        pkt->senderState = new AddrMapperSenderState(senderState, orig_addr);
    }

    pkt->setAddr(remapAddr(orig_addr));

    // Attempt to send the packet (always succeeds for inhibited
    // packets)
    bool successful = masterPort.sendTimingReq(pkt);

    // If not successful, restore the sender state
    if (!successful && needsResponse) {
        delete pkt->senderState;
        pkt->senderState = senderState;
    }

    return successful;
}

bool
AddrMapper::recvTimingResp(PacketPtr pkt)
{
    AddrMapperSenderState* receivedState =
        dynamic_cast<AddrMapperSenderState*>(pkt->senderState);

    // Restore initial sender state
    if (receivedState == NULL)
        panic("AddrMapper %s got a response without sender state\n",
              name());

    Addr remapped_addr = pkt->getAddr();

    // Restore the state and address
    pkt->senderState = receivedState->origSenderState;
    pkt->setAddr(receivedState->origAddr);

    // Attempt to send the packet
    bool successful = slavePort.sendTimingResp(pkt);

    // If packet successfully sent, delete the sender state, otherwise
    // restore state
    if (successful) {
        delete receivedState;
    } else {
        // Don't delete anything and let the packet look like we did
        // not touch it
        pkt->senderState = receivedState;
        pkt->setAddr(remapped_addr);
    }
    return successful;
}

void
AddrMapper::recvTimingSnoopReq(PacketPtr pkt)
{
    slavePort.sendTimingSnoopReq(pkt);
}

bool
AddrMapper::recvTimingSnoopResp(PacketPtr pkt)
{
    return masterPort.sendTimingSnoopResp(pkt);
}

bool
AddrMapper::isSnooping() const
{
    if (slavePort.isSnooping())
        fatal("AddrMapper doesn't support remapping of snooping requests\n");
    return false;
}

unsigned
AddrMapper::deviceBlockSizeMaster()
{
    return slavePort.peerBlockSize();
}

unsigned
AddrMapper::deviceBlockSizeSlave()
{
    return masterPort.peerBlockSize();
}

void
AddrMapper::recvRetryMaster()
{
    slavePort.sendRetry();
}

void
AddrMapper::recvRetrySlave()
{
    masterPort.sendRetry();
}

void
AddrMapper::recvRangeChange()
{
    slavePort.sendRangeChange();
}

RangeAddrMapper::RangeAddrMapper(const RangeAddrMapperParams* p) :
    AddrMapper(p),
    originalRanges(p->original_ranges),
    remappedRanges(p->remapped_ranges)
{
    if (originalRanges.size() != remappedRanges.size())
        fatal("AddrMapper: original and shadowed range list must "
              "be same size\n");

    for (size_t x = 0; x < originalRanges.size(); x++) {
        if (originalRanges[x].size() != remappedRanges[x].size())
            fatal("AddrMapper: original and shadowed range list elements"
                  " aren't all of the same size\n");
    }
}

RangeAddrMapper*
RangeAddrMapperParams::create()
{
    return new RangeAddrMapper(this);
}

Addr
RangeAddrMapper::remapAddr(Addr addr) const
{
    for (int i = 0; i < originalRanges.size(); ++i) {
        if (originalRanges[i].contains(addr)) {
            Addr offset = addr - originalRanges[i].start();
            return offset + remappedRanges[i].start();
        }
    }

    return addr;
}

AddrRangeList
RangeAddrMapper::getAddrRanges() const
{
    // Simply return the original ranges as given by the parameters
    AddrRangeList ranges(originalRanges.begin(), originalRanges.end());
    return ranges;
}

<|endoftext|>


<commit_before>#include <algorithm>
#include <string>
#include <vector>
#include <boost/optional.hpp>
#include <locale>

#include "../../../src/prompt.hh"
#include "../../../src/configuration.hh"
#include "../../../src/to_str.hh"
#include "../../../src/show_message.hh"
#include "../../../src/visual.hh"
#include "move.hh"

void mvline(contents& contents, boost::optional<int> line) {
    if(line) {
        contents.x = 0;
        int cont = line.get();
        if(cont < 0) {
            show_message("Can't move to a negative line!");
            contents.y = 0;
            return;
        }
        contents.y = cont;
        if(cont >= contents.cont.size()) {
            contents.y = contents.cont.size() - 1;
            show_message("Can't move past end of buffer!");
        }
    } else {
        while(true) {
            std::string str = prompt("Goto line: ");
            try {
                int res = std::stoi(str);
                mvline(contents, res);
                return;
            } catch(std::invalid_argument) {
                continue;
            }
        }
    }
}
void mv(contents& contents, unsigned long _y, unsigned long _x) {
    contents.y = _y;
    contents.x = _x;
    if((long) contents.y < 0) contents.y = 0;
    if(contents.y >= contents.cont.size())
        contents.y = contents.cont.size() - 1;
    if((long) contents.x < 0) contents.x = 0;
    if(contents.x >= contents.cont[contents.y].size())
        contents.x = contents.cont[contents.y].size() - 1;
}

void mvrel(contents& contents, long y, long x) {
    if(y < 0) mvu(contents,-y);
    else      mvd(contents, y);
    if(x < 0) mvb(contents,-x);
    else      mvf(contents, x);
}

void mvcol(contents& contents, boost::optional<int> col) {
    if(col) {
        unsigned int len = contents.cont[contents.y].length();
        if(len >= col.get()) {
            contents.x = col.get();
            contents.waiting_for_desired = false;
        } else {
            show_message((std::string("Can't move to column: ")
                          + int_to_str(col.get())).c_str());
        }
    } else {
        while(true) {
            std::string str = prompt("Goto column: ");
            try {
                int res = std::stoi(str);
                mvcol(contents, res);
                return;
            } catch(std::invalid_argument) {
                continue;
            }
        }
    }
}

void mvsot(contents& contents, boost::optional<int> op) {
    mvsol(contents, op);
    const std::string& str = contents.cont[contents.y];
    for(unsigned int i = 0; i < str.length(); i++) {
        if(str[i] == ' ' || str[i] == '\t')
            mvf(contents, op);
        else break;
    }
}

void mveol(contents& contents, boost::optional<int>) {
    mvcol(contents,contents.cont[contents.y].length() - 1);
}
void mvsol(contents& contents, boost::optional<int>) {
    mvcol(contents,0);
}

void mvsop(contents& contents, boost::optional<int>) {
    contents.y = 0;
    contents.x = 0;
    contents.waiting_for_desired = false;
    contents.y_offset = 0;
}
void mveop(contents& contents, boost::optional<int>) {
    contents.y = contents.cont.size() - 1;
    contents.x = 0;
    contents.y_offset = contents.y - contents.max_y + 2;
    contents.waiting_for_desired = false;
}

void mvd(contents& contents, boost::optional<int> op) {
    int times = op ? op.get() : 1;
    if(contents.y + times < 0 || contents.y + times >= contents.cont.size()) {
        show_message("Can't move to that location (start/end of buffer)");
        return;
    }
    int vis = to_visual(contents.cont[contents.y],contents.x);
    contents.y += times;
    unsigned int len = contents.cont[contents.y].length();
    if(contents.waiting_for_desired) {
        if((int)contents.x < 0) {
            contents.x = len - 1;
            unsigned int vis = from_visual(contents.cont[contents.y],
                                           contents.desired_x);
            if(vis < contents.x) {
                contents.x = vis;
                contents.waiting_for_desired = false;
            }
        } else if(contents.x >= len) {
            contents.x = len - 1;
        } else if((contents.desired_x > contents.x
                   && contents.desired_x < len)
                  || contents.desired_x == 0) {
            // x  desired  len
            contents.x = contents.desired_x;
            contents.waiting_for_desired = false;
        } else {
            // x  len  desired
            contents.x = len - 1;
        }
    } else if(len <= contents.x && len > 0) {
        contents.waiting_for_desired = true;
        contents.desired_x = contents.x;
        contents.x = len - 1;
    } else {
        int des = contents.x;
        contents.x = from_visual(contents.cont[contents.y],vis);
        if(len == 0) {
            contents.waiting_for_desired = true;
            contents.desired_x = des;
        }
    }
    contents.x = (long) contents.x >= 0 ? contents.x : 0;
    if(contents.y - contents.y_offset >= contents.max_y)
        contents.y_offset = contents.y - contents.y_offset + 1;
    if(contents.y < contents.y_offset)
        contents.y_offset = contents.y;
}
void mvu(contents& contents, boost::optional<int> op) {
    if(op) mvd(contents,-op.get());
    else mvd(contents,-1);
}

inline static bool isDeliminator(char ch) {
    return std::find(DELIMINATORS.begin(), DELIMINATORS.end(), ch)
                                        != DELIMINATORS.end();
}
inline static bool isWhitespace(char ch) {
    static const std::locale loc;
    return std::isspace(ch, loc);
}
void mvfw(contents& contents, boost::optional<int> op) {
    if(op && op.get() < 0) return mvbw(contents, op.get() * -1);
    int num = op ? op.get() : 1;
    if(num == 0 || num == -0) return;
    if(num < 0) return mvbw(contents, -op.get());
    //if deliminator then move forward until not deliminator then move over whitespace
    //else move foward until (whitespace -> move till not whitespace) or (deliminator -> stop)
    #define boundsCheck if(contents.y >= contents.cont.size() || \
                           (contents.y == contents.cont.size() - 1 &&   \
                            contents.x >= contents.cont[contents.y].size())) return;
    #define ch contents.cont[contents.y][contents.x]
    if(isDeliminator(ch)) {
        do {
            mvf(contents);
            boundsCheck;
        } while(isDeliminator(ch));
        while(isWhitespace(ch)) {
            mvf(contents);
            boundsCheck;
        }
    } else {
        while(!isDeliminator(ch) and !isWhitespace(ch)) {
            mvf(contents);
            boundsCheck;
        }
        if(isWhitespace(ch)) {
            while(isWhitespace(ch)) {
                mvf(contents);
                boundsCheck;
            }
        } else {
            while(isDeliminator(ch)) {
                mvf(contents);
                boundsCheck;
            }
        }
    }
    #undef boundsCheck
    if(num > 0) mvfw(contents,num - 1);
}
void mvfeow(contents& contents, boost::optional<int> op) {
    //move at least one forward
    //move over non deliminators
    //move over deliminators
}
void mvbw(contents& contents, boost::optional<int> op) {
    //move back one then
    //if delimitor then move back until no delimitor
    //else if whitespace then move back until not whitespace then
    //   move back consistently over delimitors or word chars
    //else /*word char*/ move back until not word char or
    //   whitespace
    //move forward one
}

inline static unsigned int fixLen(unsigned int len) {
    return len ? len : 1;
}
void mvf(contents& contents, boost::optional<int> op) {
    int times = op ? op.get() : 1;
    long newx = contents.x + times;
    try {
        while(fixLen(contents.cont.at(contents.y).length()) <= newx) {
            newx -= fixLen(contents.cont[contents.y].length());
            contents.y++;
        }
    } catch(...) { }
    if(contents.y >= contents.cont.size()) contents.y = contents.cont.size()-1;
    if(contents.x < 0) contents.x = 0;
    else      contents.x = newx;
    contents.waiting_for_desired = false;
}
void mvb(contents& contents, boost::optional<int> op) {
    int times = op ? op.get() : 1;
    if(contents.y == 0 && contents.x == 0) return;
    long newx = contents.x - times;
    try {
        while(newx < 0) {
            contents.y--;
            newx += fixLen(contents.cont.at(contents.y).length());
        }
    } catch(...) { }
    if(newx < 0) contents.x = 0;
    else         contents.x = newx;
    contents.waiting_for_desired = false;
}
<commit_msg>Align text for ``move.cc``<commit_after>#include <algorithm>
#include <string>
#include <vector>
#include <boost/optional.hpp>
#include <locale>

#include "../../../src/prompt.hh"
#include "../../../src/configuration.hh"
#include "../../../src/to_str.hh"
#include "../../../src/show_message.hh"
#include "../../../src/visual.hh"
#include "move.hh"

void mvline(contents& contents, boost::optional<int> line) {
    if(line) {
        contents.x = 0;
        int cont = line.get();
        if(cont < 0) {
            show_message("Can't move to a negative line!");
            contents.y = 0;
            return;
        }
        contents.y = cont;
        if(cont >= contents.cont.size()) {
            contents.y = contents.cont.size() - 1;
            show_message("Can't move past end of buffer!");
        }
    } else {
        while(true) {
            std::string str = prompt("Goto line: ");
            try {
                int res = std::stoi(str);
                mvline(contents, res);
                return;
            } catch(std::invalid_argument) {
                continue;
            }
        }
    }
}
void mv(contents& contents, unsigned long _y, unsigned long _x) {
    contents.y = _y;
    contents.x = _x;
    if((long) contents.y < 0) contents.y = 0;
    if(contents.y >= contents.cont.size())
        contents.y = contents.cont.size() - 1;
    if((long) contents.x < 0) contents.x = 0;
    if(contents.x >= contents.cont[contents.y].size())
        contents.x = contents.cont[contents.y].size() - 1;
}

void mvrel(contents& contents, long y, long x) {
    if(y < 0) mvu(contents,-y);
    else      mvd(contents, y);
    if(x < 0) mvb(contents,-x);
    else      mvf(contents, x);
}

void mvcol(contents& contents, boost::optional<int> col) {
    if(col) {
        unsigned int len = contents.cont[contents.y].length();
        if(len >= col.get()) {
            contents.x = col.get();
            contents.waiting_for_desired = false;
        } else {
            show_message((std::string("Can't move to column: ")
                          + int_to_str(col.get())).c_str());
        }
    } else {
        while(true) {
            std::string str = prompt("Goto column: ");
            try {
                int res = std::stoi(str);
                mvcol(contents, res);
                return;
            } catch(std::invalid_argument) {
                continue;
            }
        }
    }
}

void mvsot(contents& contents, boost::optional<int> op) {
    mvsol(contents, op);
    const std::string& str = contents.cont[contents.y];
    for(unsigned int i = 0; i < str.length(); i++) {
        if(str[i] == ' ' || str[i] == '\t')
            mvf(contents, op);
        else break;
    }
}

void mveol(contents& contents, boost::optional<int>) {
    mvcol(contents,contents.cont[contents.y].length() - 1);
}
void mvsol(contents& contents, boost::optional<int>) {
    mvcol(contents,0);
}

void mvsop(contents& contents, boost::optional<int>) {
    contents.y = 0;
    contents.x = 0;
    contents.waiting_for_desired = false;
    contents.y_offset = 0;
}
void mveop(contents& contents, boost::optional<int>) {
    contents.y = contents.cont.size() - 1;
    contents.x = 0;
    contents.y_offset = contents.y - contents.max_y + 2;
    contents.waiting_for_desired = false;
}

void mvd(contents& contents, boost::optional<int> op) {
    int times = op ? op.get() : 1;
    if(contents.y + times < 0 || contents.y + times >= contents.cont.size()) {
        show_message("Can't move to that location (start/end of buffer)");
        return;
    }
    int vis = to_visual(contents.cont[contents.y],contents.x);
    contents.y += times;
    unsigned int len = contents.cont[contents.y].length();
    if(contents.waiting_for_desired) {
        if((int)contents.x < 0) {
            contents.x = len - 1;
            unsigned int vis = from_visual(contents.cont[contents.y],
                                           contents.desired_x);
            if(vis < contents.x) {
                contents.x = vis;
                contents.waiting_for_desired = false;
            }
        } else if(contents.x >= len) {
            contents.x = len - 1;
        } else if((contents.desired_x > contents.x
                   && contents.desired_x < len)
                  || contents.desired_x == 0) {
            // x  desired  len
            contents.x = contents.desired_x;
            contents.waiting_for_desired = false;
        } else {
            // x  len  desired
            contents.x = len - 1;
        }
    } else if(len <= contents.x && len > 0) {
        contents.waiting_for_desired = true;
        contents.desired_x = contents.x;
        contents.x = len - 1;
    } else {
        int des = contents.x;
        contents.x = from_visual(contents.cont[contents.y],vis);
        if(len == 0) {
            contents.waiting_for_desired = true;
            contents.desired_x = des;
        }
    }
    contents.x = (long) contents.x >= 0 ? contents.x : 0;
    if(contents.y - contents.y_offset >= contents.max_y)
        contents.y_offset = contents.y - contents.y_offset + 1;
    if(contents.y < contents.y_offset)
        contents.y_offset = contents.y;
}
void mvu(contents& contents, boost::optional<int> op) {
    if(op) mvd(contents,-op.get());
    else mvd(contents,-1);
}

inline static bool isDeliminator(char ch) {
    return std::find(DELIMINATORS.begin(), DELIMINATORS.end(), ch)
                                        != DELIMINATORS.end();
}
inline static bool isWhitespace(char ch) {
    static const std::locale loc;
    return std::isspace(ch, loc);
}
void mvfw(contents& contents, boost::optional<int> op) {
    if(op && op.get() < 0) return mvbw(contents, op.get() * -1);
    int num = op ? op.get() : 1;
    if(num == 0 || num == -0) return;
    if(num < 0) return mvbw(contents, -op.get());
    //if deliminator then move forward until not deliminator then move over whitespace
    //else move foward until (whitespace -> move till not whitespace) or (deliminator -> stop)
    #define boundsCheck if(contents.y >= contents.cont.size() || \
                           (contents.y == contents.cont.size() - 1 &&   \
                            contents.x >= contents.cont[contents.y].size())) return;
    #define ch contents.cont[contents.y][contents.x]
    if(isDeliminator(ch)) {
        do {
            mvf(contents);
            boundsCheck;
        } while(isDeliminator(ch));
        while(isWhitespace(ch)) {
            mvf(contents);
            boundsCheck;
        }
    } else {
        while(!isDeliminator(ch) and !isWhitespace(ch)) {
            mvf(contents);
            boundsCheck;
        }
        if(isWhitespace(ch)) {
            while(isWhitespace(ch)) {
                mvf(contents);
                boundsCheck;
            }
        } else {
            while(isDeliminator(ch)) {
                mvf(contents);
                boundsCheck;
            }
        }
    }
    #undef boundsCheck
    if(num > 0) mvfw(contents,num - 1);
}
void mvfeow(contents& contents, boost::optional<int> op) {
    //move at least one forward
    //move over non deliminators
    //move over deliminators
}
void mvbw(contents& contents, boost::optional<int> op) {
    //move back one then
    //if delimitor then move back until no delimitor
    //else if whitespace then move back until not whitespace then
    //   move back consistently over delimitors or word chars
    //else /*word char*/ move back until not word char or
    //   whitespace
    //move forward one
}

inline static unsigned int fixLen(unsigned int len) {
    return len ? len : 1;
}
void mvf(contents& contents, boost::optional<int> op) {
    int times = op ? op.get() : 1;
    long newx = contents.x + times;
    try {
        while(fixLen(contents.cont.at(contents.y).length()) <= newx) {
            newx -= fixLen(contents.cont[contents.y].length());
            contents.y++;
        }
    } catch(...) { }
    if(contents.y >= contents.cont.size()) contents.y = contents.cont.size() - 1;
    if(contents.x < 0) contents.x = 0;
    else               contents.x = newx;
    contents.waiting_for_desired = false;
}
void mvb(contents& contents, boost::optional<int> op) {
    int times = op ? op.get() : 1;
    if(contents.y == 0 && contents.x == 0) return;
    long newx = contents.x - times;
    try {
        while(newx < 0) {
            contents.y--;
            newx += fixLen(contents.cont.at(contents.y).length());
        }
    } catch(...) { }
    if(newx < 0) contents.x = 0;
    else         contents.x = newx;
    contents.waiting_for_desired = false;
}
<|endoftext|>


<commit_before>/**
 * @file   UvUtils.cpp
 * @brief  uvpp miscellaneous utilities.
 * @author zer0
 * @date   2017-05-27
 */

#include <libtbag/uvpp/UvUtils.hpp>
#include <libtbag/string/StringUtils.hpp>
#include <libtbag/log/Log.hpp>

#include <cstdlib>
#include <cstring>
#include <cassert>
#include <uv.h>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace uvpp {

char ** setupArgs(int argc, char ** argv)
{
    return ::uv_setup_args(argc, argv);
}

std::string getProcessTitle()
{
    std::size_t const BUFFER_SIZE = 256;
    char buffer[BUFFER_SIZE] = {0,};

    // If buffer is NULL or size is zero, UV_EINVAL is returned.
    // If size cannot accommodate the process title and terminating NULL character,
    // the function returns UV_ENOBUFS.
    int const CODE = ::uv_get_process_title(buffer, BUFFER_SIZE);
    if (CODE != 0) {
        tDLogE("getProcessTitle() {} error", getUvErrorName(CODE));
        return std::string();
    }
    return std::string(buffer);
}

void setProcessTitle(std::string const & title)
{
    // On platforms with a fixed size buffer for the process title
    // the contents of title will be copied to the buffer
    // and truncated if larger than the available space.
    // Other platforms will return UV_ENOMEM if they cannot allocate
    // enough space to duplicate the contents of title.
    int const CODE = ::uv_set_process_title(title.c_str());
    if (CODE != 0) {
        tDLogE("setProcessTitle() {} error", getUvErrorName(CODE));
    }
}

std::size_t getResidentSetMemory()
{
    std::size_t rss = 0;
    int const CODE = ::uv_resident_set_memory(&rss);
    if (CODE != 0) {
        tDLogE("getResidentSetMemory() {} error", getUvErrorName(CODE));
    }
    return rss;
}

double getUptime()
{
    double uptime = 0.0f;
    int const CODE = ::uv_uptime(&uptime);
    if (CODE != 0) {
        tDLogE("getUptime() {} error", getUvErrorName(CODE));
    }
    return uptime;
}

ResourceUsage getResourceUsage()
{
    uv_rusage_t rusage = {0,};
    int const CODE = ::uv_getrusage(&rusage);
    if (CODE != 0) {
        tDLogE("getResourceUsage() {} error", getUvErrorName(CODE));
    }

    ResourceUsage result;
    result.utime.sec  = rusage.ru_utime.tv_sec;
    result.utime.usec = rusage.ru_utime.tv_usec;
    result.stime.sec  = rusage.ru_stime.tv_sec;
    result.stime.usec = rusage.ru_stime.tv_usec;
    result.maxrss     = rusage.ru_maxrss;
    result.ixrss      = rusage.ru_ixrss;
    result.idrss      = rusage.ru_idrss;
    result.isrss      = rusage.ru_isrss;
    result.minflt     = rusage.ru_minflt;
    result.majflt     = rusage.ru_majflt;
    result.nswap      = rusage.ru_nswap;
    result.inblock    = rusage.ru_inblock;
    result.oublock    = rusage.ru_oublock;
    result.msgsnd     = rusage.ru_msgsnd;
    result.msgrcv     = rusage.ru_msgrcv;
    result.nsignals   = rusage.ru_nsignals;
    result.nvcsw      = rusage.ru_nvcsw;
    result.nivcsw     = rusage.ru_nivcsw;
    return result;
}

std::vector<CpuInfo> getCpuInfos()
{
    uv_cpu_info_t * infos = nullptr;
    int count = 0;

    // Gets information about the CPUs on the system.
    // The cpu_infos array will have count elements and needs to be freed with uv_free_cpu_info().
    int const CODE = ::uv_cpu_info(&infos, &count);
    if (convertUvErrorToErrWithLogging("getCpuInfos()", CODE) != E_SUCCESS) {
        return std::vector<CpuInfo>();
    }

    assert(count > 0);
    std::vector<CpuInfo> result(static_cast<std::size_t>(count));

    uv_cpu_info_t * cursor = infos;
    for (int i = 0; i < count; ++i, ++cursor) {
        result[i].model.assign(cursor->model);
        result[i].speed = cursor->speed;
        result[i].times.user = cursor->cpu_times.user;
        result[i].times.nice = cursor->cpu_times.nice;
        result[i].times.sys  = cursor->cpu_times.sys ;
        result[i].times.idle = cursor->cpu_times.idle;
        result[i].times.irq  = cursor->cpu_times.irq ;
    }

    // Frees the cpu_infos array previously allocated with uv_cpu_info().
    ::uv_free_cpu_info(infos, count);

    return result;
}

std::vector<InterfaceAddress> getInterfaceAddresses()
{
    uv_interface_address_t * infos = nullptr;
    int count = 0;

    // Gets address information about the network interfaces on the system.
    // An array of count elements is allocated and returned in addresses.
    // It must be freed by the user, calling uv_free_interface_addresses().
    int const CODE = uv_interface_addresses(&infos, &count);
    if (convertUvErrorToErrWithLogging("getInterfaceAddresses()", CODE) != E_SUCCESS) {
        return std::vector<InterfaceAddress>();
    }

    assert(count >= 0);
    std::vector<InterfaceAddress> result(static_cast<std::size_t>(count));

    uv_interface_address_t * cursor = infos;
    for (int i = 0; i < count; ++i, ++cursor) {
        result[i].name.assign(cursor->name);

        static_assert(PHYSICAL_ADDRESS_SIZE == sizeof(cursor->phys_addr),
                      "The sizes of PHYSICAL_ADDRESS_SIZE and uv_interface_address_s.phys_addr should be the same.");
        for (int pi = 0; pi < result[i].physical_address.max_size(); ++pi) {
            result[i].physical_address[pi] = cursor->phys_addr[pi];
        }

        result[i].is_internal = (cursor->is_internal != 0 ? true : false);

        static_assert(sizeof(result[i].address) == sizeof(cursor->address),
                      "The sizes of InterfaceAddress.address and uv_interface_address_s.address should be the same.");
        static_assert(sizeof(result[i].netmask) == sizeof(cursor->netmask),
                      "The sizes of InterfaceAddress.netmask and uv_interface_address_s.netmask should be the same.");
        static_assert(sizeof(SocketAddress) == sizeof(cursor->address) && sizeof(SocketAddress) == sizeof(cursor->netmask),
                      "The sizes of SocketAddress and address and netmask should be the same.");

        ::memcpy(&result[i].address, &cursor->address, sizeof(cursor->address));
        ::memcpy(&result[i].netmask, &cursor->netmask, sizeof(cursor->netmask));

        assert(result[i].address.in4.sin_family == result[i].address.in6.sin6_family);
        assert(result[i].netmask.in4.sin_family == result[i].netmask.in6.sin6_family);
    }

    // Free an array of uv_interface_address_t which was returned by uv_interface_addresses().
    ::uv_free_interface_addresses(infos, count);

    return result;
}

std::string convertPhysicalToString(PhysicalAddress const & physical)
{
    std::vector<uint8_t> const BUFFER(physical.begin(), physical.end());
    return string::convertByteVectorToHexString(BUFFER, std::string(), std::string(":"));
}

void changeDirectory(std::string const & dir)
{
    int const CODE = ::uv_chdir(dir.c_str());
    if (CODE != 0) {
        tDLogE("changeDirectory() {} error", getUvErrorName(CODE));
    }
}

std::vector<double> getLoadAverage()
{
    std::size_t const SIZE = 3;
    double avg[SIZE] = {0,};
    ::uv_loadavg(avg);
    return std::vector<double>({avg[0], avg[1], avg[2]});
}

Password getPassword()
{
    // The populated data includes the username, euid, gid, shell, and home directory.
    // On non-Windows systems, all data comes from getpwuid_r(3).
    // On Windows, uid and gid are set to -1 and have no meaning, and shell is NULL.
    // After successfully calling this function,
    // the memory allocated to pwd needs to be freed with uv_os_free_passwd().

    uv_passwd_t pwd = {0,};
    int const CODE = ::uv_os_get_passwd(&pwd);
    if (CODE != 0) {
        tDLogE("getPassword() {} error", getUvErrorName(CODE));
        return Password{};
    }

    Password result;
    if (pwd.username != nullptr) {
        result.username.assign(pwd.username);
    }
    if (pwd.shell != nullptr) {
        result.shell.assign(pwd.shell);
    }
    if (pwd.homedir != nullptr) {
        result.homedir.assign(pwd.homedir);
    }
    result.uid = pwd.uid;
    result.gid = pwd.gid;

    // Frees the pwd memory previously allocated with uv_os_get_passwd().
    ::uv_os_free_passwd(&pwd);

    return result;
}

uint64_t getTotalMemory()
{
    return ::uv_get_total_memory();
}

uint64_t getHighResolutionTime()
{
    // It is relative to an arbitrary time in the past.
    // It is not related to the time of day and therefore not subject to clock drift.
    // The primary use is for measuring performance between intervals.
    //
    // Not every platform can support nanosecond resolution;
    // however, this value will always be in nanoseconds.
    return ::uv_hrtime();
}

Err getEnv(std::string const & name, std::string & value)
{
    char * env_value = ::getenv(name.c_str());
    if (env_value != nullptr) {
        value = std::string(env_value);
        return E_SUCCESS;
    }
    return E_ENFOUND;
}

Err setEnv(std::string const & name, std::string const & value)
{
    tDLogE("setEnv() Function not implemented.");
    return E_ENOSYS;
}

Err unsetEnv(std::string const & name)
{
    tDLogE("unsetEnv() Function not implemented.");
    return E_ENOSYS;
}

std::string getHostName()
{
    tDLogE("getHostName() Function not implemented.");
    return std::string();
}

} // namespace uvpp

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

<commit_msg>Implementation of environment variables related features in the UvUtils package.<commit_after>/**
 * @file   UvUtils.cpp
 * @brief  uvpp miscellaneous utilities.
 * @author zer0
 * @date   2017-05-27
 */

#include <libtbag/uvpp/UvUtils.hpp>
#include <libtbag/string/StringUtils.hpp>
#include <libtbag/log/Log.hpp>

#include <cstdlib>
#include <cstring>
#include <cassert>
#include <uv.h>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace uvpp {

char ** setupArgs(int argc, char ** argv)
{
    return ::uv_setup_args(argc, argv);
}

std::string getProcessTitle()
{
    std::size_t const BUFFER_SIZE = 256;
    char buffer[BUFFER_SIZE] = {0,};

    // If buffer is NULL or size is zero, UV_EINVAL is returned.
    // If size cannot accommodate the process title and terminating NULL character,
    // the function returns UV_ENOBUFS.
    int const CODE = ::uv_get_process_title(buffer, BUFFER_SIZE);
    if (CODE != 0) {
        tDLogE("getProcessTitle() {} error", getUvErrorName(CODE));
        return std::string();
    }
    return std::string(buffer);
}

void setProcessTitle(std::string const & title)
{
    // On platforms with a fixed size buffer for the process title
    // the contents of title will be copied to the buffer
    // and truncated if larger than the available space.
    // Other platforms will return UV_ENOMEM if they cannot allocate
    // enough space to duplicate the contents of title.
    int const CODE = ::uv_set_process_title(title.c_str());
    if (CODE != 0) {
        tDLogE("setProcessTitle() {} error", getUvErrorName(CODE));
    }
}

std::size_t getResidentSetMemory()
{
    std::size_t rss = 0;
    int const CODE = ::uv_resident_set_memory(&rss);
    if (CODE != 0) {
        tDLogE("getResidentSetMemory() {} error", getUvErrorName(CODE));
    }
    return rss;
}

double getUptime()
{
    double uptime = 0.0f;
    int const CODE = ::uv_uptime(&uptime);
    if (CODE != 0) {
        tDLogE("getUptime() {} error", getUvErrorName(CODE));
    }
    return uptime;
}

ResourceUsage getResourceUsage()
{
    uv_rusage_t rusage = {0,};
    int const CODE = ::uv_getrusage(&rusage);
    if (CODE != 0) {
        tDLogE("getResourceUsage() {} error", getUvErrorName(CODE));
    }

    ResourceUsage result;
    result.utime.sec  = rusage.ru_utime.tv_sec;
    result.utime.usec = rusage.ru_utime.tv_usec;
    result.stime.sec  = rusage.ru_stime.tv_sec;
    result.stime.usec = rusage.ru_stime.tv_usec;
    result.maxrss     = rusage.ru_maxrss;
    result.ixrss      = rusage.ru_ixrss;
    result.idrss      = rusage.ru_idrss;
    result.isrss      = rusage.ru_isrss;
    result.minflt     = rusage.ru_minflt;
    result.majflt     = rusage.ru_majflt;
    result.nswap      = rusage.ru_nswap;
    result.inblock    = rusage.ru_inblock;
    result.oublock    = rusage.ru_oublock;
    result.msgsnd     = rusage.ru_msgsnd;
    result.msgrcv     = rusage.ru_msgrcv;
    result.nsignals   = rusage.ru_nsignals;
    result.nvcsw      = rusage.ru_nvcsw;
    result.nivcsw     = rusage.ru_nivcsw;
    return result;
}

std::vector<CpuInfo> getCpuInfos()
{
    uv_cpu_info_t * infos = nullptr;
    int count = 0;

    // Gets information about the CPUs on the system.
    // The cpu_infos array will have count elements and needs to be freed with uv_free_cpu_info().
    int const CODE = ::uv_cpu_info(&infos, &count);
    if (convertUvErrorToErrWithLogging("getCpuInfos()", CODE) != E_SUCCESS) {
        return std::vector<CpuInfo>();
    }

    assert(count > 0);
    std::vector<CpuInfo> result(static_cast<std::size_t>(count));

    uv_cpu_info_t * cursor = infos;
    for (int i = 0; i < count; ++i, ++cursor) {
        result[i].model.assign(cursor->model);
        result[i].speed = cursor->speed;
        result[i].times.user = cursor->cpu_times.user;
        result[i].times.nice = cursor->cpu_times.nice;
        result[i].times.sys  = cursor->cpu_times.sys ;
        result[i].times.idle = cursor->cpu_times.idle;
        result[i].times.irq  = cursor->cpu_times.irq ;
    }

    // Frees the cpu_infos array previously allocated with uv_cpu_info().
    ::uv_free_cpu_info(infos, count);

    return result;
}

std::vector<InterfaceAddress> getInterfaceAddresses()
{
    uv_interface_address_t * infos = nullptr;
    int count = 0;

    // Gets address information about the network interfaces on the system.
    // An array of count elements is allocated and returned in addresses.
    // It must be freed by the user, calling uv_free_interface_addresses().
    int const CODE = uv_interface_addresses(&infos, &count);
    if (convertUvErrorToErrWithLogging("getInterfaceAddresses()", CODE) != E_SUCCESS) {
        return std::vector<InterfaceAddress>();
    }

    assert(count >= 0);
    std::vector<InterfaceAddress> result(static_cast<std::size_t>(count));

    uv_interface_address_t * cursor = infos;
    for (int i = 0; i < count; ++i, ++cursor) {
        result[i].name.assign(cursor->name);

        static_assert(PHYSICAL_ADDRESS_SIZE == sizeof(cursor->phys_addr),
                      "The sizes of PHYSICAL_ADDRESS_SIZE and uv_interface_address_s.phys_addr should be the same.");
        for (int pi = 0; pi < result[i].physical_address.max_size(); ++pi) {
            result[i].physical_address[pi] = cursor->phys_addr[pi];
        }

        result[i].is_internal = (cursor->is_internal != 0 ? true : false);

        static_assert(sizeof(result[i].address) == sizeof(cursor->address),
                      "The sizes of InterfaceAddress.address and uv_interface_address_s.address should be the same.");
        static_assert(sizeof(result[i].netmask) == sizeof(cursor->netmask),
                      "The sizes of InterfaceAddress.netmask and uv_interface_address_s.netmask should be the same.");
        static_assert(sizeof(SocketAddress) == sizeof(cursor->address) && sizeof(SocketAddress) == sizeof(cursor->netmask),
                      "The sizes of SocketAddress and address and netmask should be the same.");

        ::memcpy(&result[i].address, &cursor->address, sizeof(cursor->address));
        ::memcpy(&result[i].netmask, &cursor->netmask, sizeof(cursor->netmask));

        assert(result[i].address.in4.sin_family == result[i].address.in6.sin6_family);
        assert(result[i].netmask.in4.sin_family == result[i].netmask.in6.sin6_family);
    }

    // Free an array of uv_interface_address_t which was returned by uv_interface_addresses().
    ::uv_free_interface_addresses(infos, count);

    return result;
}

std::string convertPhysicalToString(PhysicalAddress const & physical)
{
    std::vector<uint8_t> const BUFFER(physical.begin(), physical.end());
    return libtbag::string::convertByteVectorToHexString(BUFFER, std::string(), std::string(":"));
}

void changeDirectory(std::string const & dir)
{
    int const CODE = ::uv_chdir(dir.c_str());
    if (CODE != 0) {
        tDLogE("changeDirectory() {} error", getUvErrorName(CODE));
    }
}

std::vector<double> getLoadAverage()
{
    std::size_t const SIZE = 3;
    double avg[SIZE] = {0,};
    ::uv_loadavg(avg);
    return std::vector<double>({avg[0], avg[1], avg[2]});
}

Password getPassword()
{
    // The populated data includes the username, euid, gid, shell, and home directory.
    // On non-Windows systems, all data comes from getpwuid_r(3).
    // On Windows, uid and gid are set to -1 and have no meaning, and shell is NULL.
    // After successfully calling this function,
    // the memory allocated to pwd needs to be freed with uv_os_free_passwd().

    uv_passwd_t pwd = {0,};
    int const CODE = ::uv_os_get_passwd(&pwd);
    if (CODE != 0) {
        tDLogE("getPassword() {} error", getUvErrorName(CODE));
        return Password{};
    }

    Password result;
    if (pwd.username != nullptr) {
        result.username.assign(pwd.username);
    }
    if (pwd.shell != nullptr) {
        result.shell.assign(pwd.shell);
    }
    if (pwd.homedir != nullptr) {
        result.homedir.assign(pwd.homedir);
    }
    result.uid = pwd.uid;
    result.gid = pwd.gid;

    // Frees the pwd memory previously allocated with uv_os_get_passwd().
    ::uv_os_free_passwd(&pwd);

    return result;
}

uint64_t getTotalMemory()
{
    return ::uv_get_total_memory();
}

uint64_t getHighResolutionTime()
{
    // It is relative to an arbitrary time in the past.
    // It is not related to the time of day and therefore not subject to clock drift.
    // The primary use is for measuring performance between intervals.
    //
    // Not every platform can support nanosecond resolution;
    // however, this value will always be in nanoseconds.
    return ::uv_hrtime();
}

Err getEnv(std::string const & name, std::string & value)
{
#if (UV_VERSION_MAJOR >= 1) && (UV_VERSION_MINOR >= 12)
    std::size_t size = 0;
    int code = ::uv_os_getenv(name.c_str(), nullptr, &size);
    if (code != UV_ENOBUFS) {
        return libtbag::convertUvErrorToErr(code);
    }
    assert(size >= 1);
    assert(code == UV_ENOBUFS);
    std::vector<char> buffer(size);
    code = ::uv_os_getenv(name.c_str(), &value[0], &size);
    if (code == 0) {
        value = std::string(&buffer[0]);
        return E_SUCCESS;
    }
    return libtbag::convertUvErrorToErr(code);
#else
    char * env_value = ::getenv(name.c_str());
    if (env_value != nullptr) {
        value = std::string(env_value);
        return E_SUCCESS;
    }
    return E_ENFOUND;
#endif
}

Err setEnv(std::string const & name, std::string const & value)
{
#if (UV_VERSION_MAJOR >= 1) && (UV_VERSION_MINOR >= 12)
    return libtbag::convertUvErrorToErr(::uv_os_setenv(name.c_str(), value.c_str()));
#else
    tDLogE("setEnv() Function not implemented.");
    return E_ENOSYS;
#endif
}

Err unsetEnv(std::string const & name)
{
#if (UV_VERSION_MAJOR >= 1) && (UV_VERSION_MINOR >= 12)
    return libtbag::convertUvErrorToErr(::uv_os_unsetenv(name.c_str()));
#else
    tDLogE("unsetEnv() Function not implemented.");
    return E_ENOSYS;
#endif
}

std::string getHostName()
{
#if (UV_VERSION_MAJOR >= 1) && (UV_VERSION_MINOR >= 16)
    char buffer[UV_MAXHOSTNAMESIZE] = {0,};
    std::size_t size = UV_MAXHOSTNAMESIZE;
    int const CODE = ::uv_os_gethostname(buffer, &size);
    if (CODE == 0) {
        return std::string(&buffer[0]);
    }
    return std::string();
#elif (UV_VERSION_MAJOR >= 1) && (UV_VERSION_MINOR >= 12)
    std::size_t size = 0;
    int code = ::uv_os_gethostname(nullptr, &size);
    if (code != UV_ENOBUFS) {
        return std::string();
    }

    assert(size >= 1);
    assert(code == UV_ENOBUFS);
    std::vector<char> buffer(size);
    code = ::uv_os_gethostname(&buffer[0], &size);
    if (code == 0) {
        return std::string(&buffer[0]);
    }
    return std::string();
#else
    tDLogE("getHostName() Function not implemented.");
    return std::string();
#endif
}

} // namespace uvpp

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

<|endoftext|>


<commit_before>#include "mutation.h"
#include "editdistance.h"
#include <iostream>
#include <fstream>
#include "util.h"
#include <string.h>
#include "builtinmutation.h"
#include <sstream>
#include "globalsettings.h"

Mutation::Mutation(string name, string left, string center, string right){
	//we shift some bases from left and right to center to require 100% match of these bases
    mShift = 2;
    mLeft = left.substr(0, left.length()-mShift);
	mCenter = left.substr(left.length()-mShift, mShift) + center + right.substr(0, mShift);
    mRight = right.substr(mShift, right.length()-mShift);
    mPattern = left + center + right;
    mName = name;
}

Match* Mutation::searchInRead(Read* r, int distanceReq, int qualReq){
    char phredQualReq= (char)(qualReq + 33);
    int readLen = r->mSeq.length();
    int lLen = mLeft.length();
    int cLen = mCenter.length();
    int rLen = mRight.length();
    int pLen = mPattern.length();
    string seq = r->mSeq.mStr;
    const char* seqData = seq.c_str();
    const char* centerData = mCenter.c_str();
    const char* patternData = mPattern.c_str();
    const char* qualData = r->mQuality.c_str();
    // we should ignore the mutations in the exact edge since there usualy exists errors
    const int margin = 0;
    for(int start = margin; start + cLen + margin <= readLen; start++){
        int lComp = min(start, lLen);
        // check string identity in a fast way
        bool identical = true;
        for (int i=0;i<cLen;i++){
            if (seqData[start + i] != centerData[i]){
                identical = false;
                break;
            }
        }
        if(!identical)
            continue;

        // check quality in a fast way
        bool qualityPassed = true;
        for (int i=mShift; i<cLen-mShift; i++){
            if (qualData[start + i] < phredQualReq){
                qualityPassed = false;
                break;
            }
        }
        if(!qualityPassed)
            continue;
        int edLen = min(pLen - (lLen - lComp), readLen - (start - lComp));
        // too short
        if(edLen < 15)
            continue;
        int ed = edit_distance(seqData + start - lComp, edLen, patternData + lLen - lComp, edLen);
        if ( ed <= distanceReq){
            return new Match(r, start, ed);
        }
    }
    return NULL;
}

vector<Mutation> Mutation::parseCsv(string filename) {
    ifstream file;
    file.open(filename.c_str(), ifstream::in);
    const int maxLine = 1000;
    char line[maxLine];
    vector<Mutation> mutations;
    while(file.getline(line, maxLine)){
        // trim \n, \r or \r\n in the tail
        int readed = strlen(line);
        if(readed >=2 ){
            if(line[readed-1] == '\n' || line[readed-1] == '\r'){
                line[readed-1] = '\0';
                if(line[readed-2] == '\r')
                    line[readed-2] = '\0';
            }
        }
        string linestr(line);
        vector<string> splitted;
        split(linestr, splitted, ",");
        // a valid line need 4 columns: name, left, center, right
        if(splitted.size()<4)
            continue;
        // comment line
        if(starts_with(splitted[0], "#"))
            continue;
        string name = trim(splitted[0]);
        string left = trim(splitted[1]);
        string center = trim(splitted[2]);
        string right = trim(splitted[3]);
        Mutation mut(name, left, center, right);
        if(left.length()<10){
            cerr << "WARNING: skip following mutation since its left part < 10bp"<<endl<<"\t";
            mut.print();
        }
        else if(right.length()<10){
            cerr << "WARNING: skip following mutation since its right part < 10bp"<<endl<<"\t";
            mut.print();
        }
        else if(left.length() + center.length() + right.length() < 30){
            cerr << "WARNING: skip following mutation since its (left+center+right) < 30bp"<<endl<<"\t";
            mut.print();
        }
        else {
            mutations.push_back(mut);
        }
    }
    file.close();
    if(mutations.size() <= 0){
        cerr<<"No mutation will be scanned"<<endl;
    }
    return mutations;
}

vector<Mutation> Mutation::parseBuiltIn() {
    vector<Mutation> mutations;
    vector<string> lines;
    split(BUILT_IN_MUTATIONS, lines, "\n");
    for(int i=0;i<lines.size();i++){
        string linestr = lines[i];
        vector<string> splitted;
        split(linestr, splitted, ",");
        // a valid line need 4 columns: name, left, center, right
        if(splitted.size()<4)
            continue;
        // comment line
        if(starts_with(splitted[0], "#"))
            continue;
        string name = trim(splitted[0]);
        string left = trim(splitted[1]);
        string center = trim(splitted[2]);
        string right = trim(splitted[3]);
        Mutation mut(name, left, center, right);
        mutations.push_back(mut);
    }
    if(mutations.size() <= 0){
        cerr<<"No mutation will be scanned"<<endl;
    }
    return mutations;
}

vector<Mutation> Mutation::parseVcf(string vcfFile, string refFile) {
    vector<Mutation> mutations;
    VcfReader vr(vcfFile);
    vr.readAll();
    vector<Variant> variants = vr.variants();

    bool markedOnly = GlobalSettings::markedOnlyForVCF;

    const int vcfMax = 100;
    if(variants.size() > vcfMax && markedOnly==false){
        cerr<<"Your VCF has more than "<<vcfMax<<" records, this will make MutScan take too long to complete the scan." << endl;
        cerr<<"Please use a smaller VCF"<<endl;
        cerr<<"Or use --mark option, and mark the wanted VCF records with FILTER column as M"<<endl;
        cerr<<"Example (note the M in the FILTER column):"<<endl;
        cerr<<"#CHROM   POS     ID          REF ALT QUAL  FILTER  INFO"<<endl;
        cerr<<"1        69224   COSM3677745 A   C   .     M       This record will be scanned"<<endl;
        cerr<<"1        880950  COSM3493111 G   A   .     .       This record will be skipped"<<endl;
        cerr<<endl;
        exit(-1);
    }

    FastaReader fr(refFile);
    fr.readAll();
    map<string, string> ref = fr.contigs();

    for(int i=0;i<variants.size();i++) {
        Variant& v = variants[i];
        // skip the unmasked if markedOnly flag is set true
        if(markedOnly && (v.filter!="m" && v.filter!="M"))
            continue;
        string chrom = v.chrom;
        if(!starts_with(chrom, "chr"))
            chrom = "chr" + chrom;
        // the contig is not in reference
        if(ref.count(chrom) == 0)
            continue;
        // the variant is out of this contig, or in the front or tail
        // note that VCF is 1-based, and string is 0-based
        if(v.pos > ref[chrom].length() + 25 + 1 || v.pos < 25 + 1)
            continue;

        string gene = v.gene();
        string aa = v.aaChange();
        string cds = v.cdsChange();

        stringstream ss;
        if(gene!="")
            ss<<gene<<"_";
        if(aa!="")
            ss<<aa<<"_";
        if(cds!="")
            ss<<cds<<"_";
        ss<<chrom<<"_"<<v.pos<<"_"<<v.ref<<">"<<v.alt;
        string name = ss.str();
        string left = ref[chrom].substr(v.pos-25-1, 25);
        string center = v.alt;
        string right = ref[chrom].substr(v.pos+v.ref.length()-1, 25);
        Mutation mut(name, left, center, right);
        cerr << name << ", " << left << ", " << center << ", " << right << endl;
        mutations.push_back(mut);
    }
    if(mutations.size() <= 0){
        cerr<<"No mutation will be scanned"<<endl;
        if(markedOnly){
            cerr<<"You are using --mark option, you should mark the wanted VCF records with FILTER as M"<<endl;
            cerr<<"Example (note the M in the FILTER column):"<<endl;
            cerr<<"#CHROM   POS     ID          REF ALT QUAL  FILTER  INFO"<<endl;
            cerr<<"1        69224   COSM3677745 A   C   .     M       This record will be scanned"<<endl;
            cerr<<"1        880950  COSM3493111 G   A   .     .       This record will be skipped"<<endl;
        } else {
            cerr<<"Your VCF contains no valid records"<<endl;
        }
        cerr<<endl;
        exit(-1);
    }
    return mutations;
}

void Mutation::print(){
    cout<<mName<<" "<<mLeft<<" "<<mCenter<<" "<<mRight<<endl;
}

void Mutation::printHtml(ofstream& file){
    file<<mName<<" "<<mLeft<<" "<<mCenter<<" "<<mRight;
}
<commit_msg>support with or without chr in VCF<commit_after>#include "mutation.h"
#include "editdistance.h"
#include <iostream>
#include <fstream>
#include "util.h"
#include <string.h>
#include "builtinmutation.h"
#include <sstream>
#include "globalsettings.h"

Mutation::Mutation(string name, string left, string center, string right){
	//we shift some bases from left and right to center to require 100% match of these bases
    mShift = 2;
    mLeft = left.substr(0, left.length()-mShift);
	mCenter = left.substr(left.length()-mShift, mShift) + center + right.substr(0, mShift);
    mRight = right.substr(mShift, right.length()-mShift);
    mPattern = left + center + right;
    mName = name;
}

Match* Mutation::searchInRead(Read* r, int distanceReq, int qualReq){
    char phredQualReq= (char)(qualReq + 33);
    int readLen = r->mSeq.length();
    int lLen = mLeft.length();
    int cLen = mCenter.length();
    int rLen = mRight.length();
    int pLen = mPattern.length();
    string seq = r->mSeq.mStr;
    const char* seqData = seq.c_str();
    const char* centerData = mCenter.c_str();
    const char* patternData = mPattern.c_str();
    const char* qualData = r->mQuality.c_str();
    // we should ignore the mutations in the exact edge since there usualy exists errors
    const int margin = 0;
    for(int start = margin; start + cLen + margin <= readLen; start++){
        int lComp = min(start, lLen);
        // check string identity in a fast way
        bool identical = true;
        for (int i=0;i<cLen;i++){
            if (seqData[start + i] != centerData[i]){
                identical = false;
                break;
            }
        }
        if(!identical)
            continue;

        // check quality in a fast way
        bool qualityPassed = true;
        for (int i=mShift; i<cLen-mShift; i++){
            if (qualData[start + i] < phredQualReq){
                qualityPassed = false;
                break;
            }
        }
        if(!qualityPassed)
            continue;
        int edLen = min(pLen - (lLen - lComp), readLen - (start - lComp));
        // too short
        if(edLen < 15)
            continue;
        int ed = edit_distance(seqData + start - lComp, edLen, patternData + lLen - lComp, edLen);
        if ( ed <= distanceReq){
            return new Match(r, start, ed);
        }
    }
    return NULL;
}

vector<Mutation> Mutation::parseCsv(string filename) {
    ifstream file;
    file.open(filename.c_str(), ifstream::in);
    const int maxLine = 1000;
    char line[maxLine];
    vector<Mutation> mutations;
    while(file.getline(line, maxLine)){
        // trim \n, \r or \r\n in the tail
        int readed = strlen(line);
        if(readed >=2 ){
            if(line[readed-1] == '\n' || line[readed-1] == '\r'){
                line[readed-1] = '\0';
                if(line[readed-2] == '\r')
                    line[readed-2] = '\0';
            }
        }
        string linestr(line);
        vector<string> splitted;
        split(linestr, splitted, ",");
        // a valid line need 4 columns: name, left, center, right
        if(splitted.size()<4)
            continue;
        // comment line
        if(starts_with(splitted[0], "#"))
            continue;
        string name = trim(splitted[0]);
        string left = trim(splitted[1]);
        string center = trim(splitted[2]);
        string right = trim(splitted[3]);
        Mutation mut(name, left, center, right);
        if(left.length()<10){
            cerr << "WARNING: skip following mutation since its left part < 10bp"<<endl<<"\t";
            mut.print();
        }
        else if(right.length()<10){
            cerr << "WARNING: skip following mutation since its right part < 10bp"<<endl<<"\t";
            mut.print();
        }
        else if(left.length() + center.length() + right.length() < 30){
            cerr << "WARNING: skip following mutation since its (left+center+right) < 30bp"<<endl<<"\t";
            mut.print();
        }
        else {
            mutations.push_back(mut);
        }
    }
    file.close();
    if(mutations.size() <= 0){
        cerr<<"No mutation will be scanned"<<endl;
    }
    return mutations;
}

vector<Mutation> Mutation::parseBuiltIn() {
    vector<Mutation> mutations;
    vector<string> lines;
    split(BUILT_IN_MUTATIONS, lines, "\n");
    for(int i=0;i<lines.size();i++){
        string linestr = lines[i];
        vector<string> splitted;
        split(linestr, splitted, ",");
        // a valid line need 4 columns: name, left, center, right
        if(splitted.size()<4)
            continue;
        // comment line
        if(starts_with(splitted[0], "#"))
            continue;
        string name = trim(splitted[0]);
        string left = trim(splitted[1]);
        string center = trim(splitted[2]);
        string right = trim(splitted[3]);
        Mutation mut(name, left, center, right);
        mutations.push_back(mut);
    }
    if(mutations.size() <= 0){
        cerr<<"No mutation will be scanned"<<endl;
    }
    return mutations;
}

vector<Mutation> Mutation::parseVcf(string vcfFile, string refFile) {
    vector<Mutation> mutations;
    VcfReader vr(vcfFile);
    vr.readAll();
    vector<Variant> variants = vr.variants();

    bool markedOnly = GlobalSettings::markedOnlyForVCF;

    const int vcfMax = 100;
    if(variants.size() > vcfMax && markedOnly==false){
        cerr<<"Your VCF has more than "<<vcfMax<<" records, this will make MutScan take too long to complete the scan." << endl;
        cerr<<"Please use a smaller VCF"<<endl;
        cerr<<"Or use --mark option, and mark the wanted VCF records with FILTER column as M"<<endl;
        cerr<<"Example (note the M in the FILTER column):"<<endl;
        cerr<<"#CHROM   POS     ID          REF ALT QUAL  FILTER  INFO"<<endl;
        cerr<<"1        69224   COSM3677745 A   C   .     M       This record will be scanned"<<endl;
        cerr<<"1        880950  COSM3493111 G   A   .     .       This record will be skipped"<<endl;
        cerr<<endl;
        exit(-1);
    }

    FastaReader fr(refFile);
    fr.readAll();
    map<string, string> ref = fr.contigs();

    for(int i=0;i<variants.size();i++) {
        Variant& v = variants[i];
        // skip the unmasked if markedOnly flag is set true
        if(markedOnly && (v.filter!="m" && v.filter!="M"))
            continue;
        string chrom = v.chrom;

        // the contig is not in reference
        if(ref.count(chrom) == 0){
            // add or remove chr to match the reference
            if(!starts_with(chrom, "chr"))
                chrom = "chr" + chrom;
            else
                chrom = chrom.substr(3, chrom.length()-3);

            if(ref.count(chrom) == 0)
                continue;
        }
        // the variant is out of this contig, or in the front or tail
        // note that VCF is 1-based, and string is 0-based
        if(v.pos > ref[chrom].length() + 25 + 1 || v.pos < 25 + 1)
            continue;

        string gene = v.gene();
        string aa = v.aaChange();
        string cds = v.cdsChange();

        stringstream ss;
        if(gene!="")
            ss<<gene<<"_";
        if(aa!="")
            ss<<aa<<"_";
        if(cds!="")
            ss<<cds<<"_";
        ss<<chrom<<"_"<<v.pos<<"_"<<v.ref<<">"<<v.alt;
        string name = ss.str();
        string left = ref[chrom].substr(v.pos-25-1, 25);
        string center = v.alt;
        string right = ref[chrom].substr(v.pos+v.ref.length()-1, 25);
        Mutation mut(name, left, center, right);
        cerr << name << ", " << left << ", " << center << ", " << right << endl;
        mutations.push_back(mut);
    }
    if(mutations.size() <= 0){
        cerr<<"No mutation will be scanned"<<endl;
        if(markedOnly){
            cerr<<"You are using --mark option, you should mark the wanted VCF records with FILTER as M"<<endl;
            cerr<<"Example (note the M in the FILTER column):"<<endl;
            cerr<<"#CHROM   POS     ID          REF ALT QUAL  FILTER  INFO"<<endl;
            cerr<<"1        69224   COSM3677745 A   C   .     M       This record will be scanned"<<endl;
            cerr<<"1        880950  COSM3493111 G   A   .     .       This record will be skipped"<<endl;
        } else {
            cerr<<"Your VCF contains no valid records"<<endl;
        }
        cerr<<endl;
        exit(-1);
    }
    return mutations;
}

void Mutation::print(){
    cout<<mName<<" "<<mLeft<<" "<<mCenter<<" "<<mRight<<endl;
}

void Mutation::printHtml(ofstream& file){
    file<<mName<<" "<<mLeft<<" "<<mCenter<<" "<<mRight;
}
<|endoftext|>


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

#include "mvf-core.h"
#include "init.h"
#include "util.h"
#include "chainparams.h"
#include "validationinterface.h"

#include <iostream>
#include <fstream>
#include <boost/filesystem.hpp>

using namespace std;

// version string identifying the consensus-relevant algorithmic changes
// so that a user can quickly see if MVF fork clients are compatible
// for test purposes (since they may diverge during development/testing).
// A new value must be chosen whenever there are changes to consensus
// relevant functionality (excepting things which are parameterized).
// Values are surnames chosen from the name list of space travelers at
// https://en.wikipedia.org/wiki/List_of_space_travelers_by_name
std::string post_fork_consensus_id = "AKIYAMA";

// actual fork height, taking into account user configuration parameters (MVHF-CORE-DES-TRIG-4)
int FinalActivateForkHeight = 0;

// actual fork id, taking into account user configuration parameters (MVHF-CORE-DES-CSIG-1)
int FinalForkId = 0;

// track whether HF has been activated before in previous run (MVHF-CORE-DES-TRIG-5)
// is set at startup based on btcfork.conf presence
bool wasMVFHardForkPreviouslyActivated = false;

// track whether HF is active (MVHF-CORE-DES-TRIG-5)
bool isMVFHardForkActive = false;

// track whether auto wallet backup might still need to be done
// this is set to true at startup if client detects fork already triggered
// otherwise when the backup is made. (MVHF-CORE-DES-WABU-1)
bool fAutoBackupDone = false;

// default suffix to append to wallet filename for auto backup (MVHF-CORE-DES-WABU-1)
std::string autoWalletBackupSuffix = "auto.@.bak";

/** Add MVF-specific command line options (MVHF-CORE-DES-TRIG-8) */
std::string ForkCmdLineHelp()
{
    std::string strUsage;
    strUsage += HelpMessageGroup(_("Bitcoin MVF-Core Options:"));

    // automatic wallet backup parameters (MVHF-CORE-DES-WABU-1)
    strUsage += HelpMessageOpt("-autobackupwalletpath=<path>", _("Automatically backup the wallet to the autobackupwalletfile path after the block specified becomes the best block (-autobackupblock). Default: Enabled"));
    strUsage += HelpMessageOpt("-autobackupblock=<n>", _("Specify the block number that triggers the automatic wallet backup. Default: forkheight-1"));

    // fork height parameter (MVHF-CORE-DES-TRIG-1)
    strUsage += HelpMessageOpt("-forkheight=<n>", strprintf(_("Block height at which to fork on active network (integer). Defaults (also minimums): mainnet:%u,testnet=%u,regtest=%u"), (unsigned)HARDFORK_HEIGHT_MAINNET, (unsigned)HARDFORK_HEIGHT_TESTNET, (unsigned)HARDFORK_HEIGHT_REGTEST));

    // fork id (MVHF-CORE-DES-CSIG-1)
    strUsage += HelpMessageOpt("-forkid=<n>", strprintf(_("Fork id to use for signature change. Value must be between 0 and %d. Default is 0x%06x (%u)"), (unsigned)MAX_HARDFORK_SIGHASH_ID, (unsigned)HARDFORK_SIGHASH_ID, (unsigned)HARDFORK_SIGHASH_ID));

    return strUsage;
}

/** Performs fork-related setup / validation actions when the program starts */
void ForkSetup(const CChainParams& chainparams)
{
    int defaultForkHeightForNetwork = 0;
    std:string activeNetworkID = chainparams.NetworkIDString();

    LogPrintf("%s: MVF: doing setup\n", __func__);
    LogPrintf("%s: MVF: consensus version = %s\n", __func__, post_fork_consensus_id);
    LogPrintf("%s: MVF: active network = %s\n", __func__, activeNetworkID);

    // determine minimum fork height according to network
    // (these are set to the same as the default fork heights for now, but could be made different)
    if (activeNetworkID == CBaseChainParams::MAIN)
        defaultForkHeightForNetwork = HARDFORK_HEIGHT_MAINNET;
    else if (activeNetworkID == CBaseChainParams::TESTNET)
        defaultForkHeightForNetwork = HARDFORK_HEIGHT_TESTNET;
    else if (activeNetworkID == CBaseChainParams::REGTEST)
        defaultForkHeightForNetwork = HARDFORK_HEIGHT_REGTEST;
    else
        throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, activeNetworkID));

    FinalActivateForkHeight = GetArg("-forkheight", defaultForkHeightForNetwork);

    FinalForkId = GetArg("-forkid", HARDFORK_SIGHASH_ID);
    // check fork id for validity (MVHF-CORE-DES-CSIG-2)
    if (FinalForkId == 0) {
        LogPrintf("MVF: Warning: fork id = 0 will result in vulnerability to replay attacks\n");
    }
    else {
        if (FinalForkId < 0 || FinalForkId > MAX_HARDFORK_SIGHASH_ID) {
            LogPrintf("MVF: Error: specified fork id (%d) is not in range 0..%u\n", FinalForkId, (unsigned)MAX_HARDFORK_SIGHASH_ID);
            StartShutdown();
        }
    }

    if (GetBoolArg("-segwitfork", DEFAULT_TRIGGER_ON_SEGWIT))
        LogPrintf("%s: MVF: Segregated Witness trigger is ENABLED\n", __func__);
    else
        LogPrintf("%s: MVF: Segregated Witness trigger is DISABLED\n", __func__);

    LogPrintf("%s: MVF: active fork height = %d\n", __func__, FinalActivateForkHeight);

    LogPrintf("%s: MVF: active fork id = 0x%06x (%d)\n", __func__, FinalForkId, FinalForkId);

    if (GetBoolArg("-force-retarget", DEFAULT_FORCE_RETARGET))
        LogPrintf("%s: MVF: force-retarget is ENABLED\n", __func__);
    else
        LogPrintf("%s: MVF: force-retarget is DISABLED\n", __func__);

    LogPrintf("%s: MVF: auto backup block = %d\n", __func__, GetArg("-autobackupblock", FinalActivateForkHeight - 1));

    // check if btcfork.conf exists (MVHF-CORE-DES-TRIG-10)
    boost::filesystem::path pathBTCforkConfigFile(BTCFORK_CONF_FILENAME);
    if (!pathBTCforkConfigFile.is_complete())
        pathBTCforkConfigFile = GetDataDir(false) / pathBTCforkConfigFile;
    if (boost::filesystem::exists(pathBTCforkConfigFile)) {
        LogPrintf("%s: MVF: found marker config file at %s - client has already forked before\n", __func__, pathBTCforkConfigFile.string().c_str());
        wasMVFHardForkPreviouslyActivated = true;
    }
    else {
        LogPrintf("%s: MVF: no marker config file at %s - client has not forked yet\n", __func__, pathBTCforkConfigFile.string().c_str());
        wasMVFHardForkPreviouslyActivated = false;
    }

    // we should always set the activation flag to false during setup
    isMVFHardForkActive = false;
}

/** Actions when the fork triggers (MVHF-CORE-DES-TRIG-6) */
// doBackup parameter default is true
void ActivateFork(int actualForkHeight, bool doBackup)
{
    LogPrintf("%s: MVF: checking whether to perform fork activation\n", __func__);
    if (!isMVFHardForkActive && !wasMVFHardForkPreviouslyActivated)  // sanity check to protect the one-off actions
    {
        LogPrintf("%s: MVF: performing fork activation actions\n", __func__);

        // set so that we capture the actual height at which it forked
        // because this can be different from user-specified configuration
        // (e.g. soft-fork activated)
        FinalActivateForkHeight = actualForkHeight;

        boost::filesystem::path pathBTCforkConfigFile(BTCFORK_CONF_FILENAME);
        if (!pathBTCforkConfigFile.is_complete())
            pathBTCforkConfigFile = GetDataDir(false) / pathBTCforkConfigFile;

        LogPrintf("%s: MVF: checking for existence of %s\n", __func__, pathBTCforkConfigFile.string().c_str());

        // remove btcfork.conf if it already exists - it shall be overwritten
        if (boost::filesystem::exists(pathBTCforkConfigFile)) {
            LogPrintf("%s: MVF: removing %s\n", __func__, pathBTCforkConfigFile.string().c_str());
            try {
                boost::filesystem::remove(pathBTCforkConfigFile);
            } catch (const boost::filesystem::filesystem_error& e) {
                LogPrintf("%s: Unable to remove pidfile: %s\n", __func__, e.what());
            }
        }
        // try to write the btcfork.conf (MVHF-CORE-DES-TRIG-10)
        LogPrintf("%s: MVF: writing %s\n", __func__, pathBTCforkConfigFile.string().c_str());
        std::ofstream  btcforkfile(pathBTCforkConfigFile.string().c_str(), std::ios::out);
        btcforkfile << "forkheight=" << FinalActivateForkHeight << "\n";
        btcforkfile << "forkid=" << FinalForkId << "\n";

        LogPrintf("%s: MVF: active fork height = %d\n", __func__, FinalActivateForkHeight);
        LogPrintf("%s: MVF: active fork id = 0x%06x (%d)\n", __func__, FinalForkId, FinalForkId);

        // MVF-Core begin MVHF-CORE-DES-WABU-3
        // check if we need to do wallet auto backup at fork block
        // this is in case of soft-fork triggered activation
        // MVF-Core TODO: reduce code duplication between this block and main.cpp:UpdateTip()
        if (doBackup && !fAutoBackupDone)
        {
            std::string strWalletBackupFile = GetArg("-autobackupwalletpath", "");
            int BackupBlock = actualForkHeight;

            //LogPrintf("MVF DEBUG: autobackupwalletpath=%s\n",strWalletBackupFile);
            //LogPrintf("MVF DEBUG: autobackupblock=%d\n",BackupBlock);

            if (GetBoolArg("-disablewallet", false))
            {
                LogPrintf("MVF: -disablewallet and -autobackupwalletpath conflict so automatic backup disabled.");
                fAutoBackupDone = true;
            }
            else {
                // Auto Backup defined, but no need to check block height since
                // this is fork activation time and we still have not backed up
                // so just get on with it
                if (GetMainSignals().BackupWalletAuto(strWalletBackupFile, BackupBlock))
                    fAutoBackupDone = true;
                else {
                    // shutdown in case of wallet backup failure (MVHF-CORE-DES-WABU-5)
                    // MVF-Core TODO: investigate if this is safe in terms of wallet flushing/closing or if more needs to be done
                    btcforkfile << "error: unable to perform automatic backup - exiting" << "\n";
                    btcforkfile.close();
                    throw std::runtime_error("CWallet::BackupWalletAuto() : Auto wallet backup failed!");
                }
            }
            btcforkfile << "autobackupblock=" << FinalActivateForkHeight << "\n";
            LogPrintf("%s: MVF: soft-forked auto backup block = %d\n", __func__, FinalActivateForkHeight);

        }
        else {
            // auto backup was already made pre-fork - emit parameters
            btcforkfile << "autobackupblock=" << GetArg("-autobackupblock", FinalActivateForkHeight - 1) << "\n";
            LogPrintf("%s: MVF: height-based auto backup block = %d\n", __func__, GetArg("-autobackupblock", FinalActivateForkHeight - 1));
        }

        // close fork parameter file
        btcforkfile.close();
    }
    // set the flag so that other code knows HF is active
    LogPrintf("%s: MVF: enabling isMVFHardForkActive\n", __func__);
    isMVFHardForkActive = true;
}

/** Actions when the fork is deactivated in reorg (MVHF-CORE-DES-TRIG-7) */
void DeactivateFork(void)
{
    LogPrintf("%s: MVF: checking whether to perform fork deactivation\n", __func__);
    if (isMVFHardForkActive)
    {
        LogPrintf("%s: MVF: performing fork deactivation actions\n", __func__);
    }
    LogPrintf("%s: MVF: disabling isMVFHardForkActive\n", __func__);
    isMVFHardForkActive = false;
}
<commit_msg>change log output for consensus id<commit_after>// Copyright (c) 2016 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// MVF-Core common objects and functions

#include "mvf-core.h"
#include "init.h"
#include "util.h"
#include "chainparams.h"
#include "validationinterface.h"

#include <iostream>
#include <fstream>
#include <boost/filesystem.hpp>

using namespace std;

// version string identifying the consensus-relevant algorithmic changes
// so that a user can quickly see if MVF fork clients are compatible
// for test purposes (since they may diverge during development/testing).
// A new value must be chosen whenever there are changes to consensus
// relevant functionality (excepting things which are parameterized).
// Values are surnames chosen from the name list of space travelers at
// https://en.wikipedia.org/wiki/List_of_space_travelers_by_name
std::string post_fork_consensus_id = "AKIYAMA";

// actual fork height, taking into account user configuration parameters (MVHF-CORE-DES-TRIG-4)
int FinalActivateForkHeight = 0;

// actual fork id, taking into account user configuration parameters (MVHF-CORE-DES-CSIG-1)
int FinalForkId = 0;

// track whether HF has been activated before in previous run (MVHF-CORE-DES-TRIG-5)
// is set at startup based on btcfork.conf presence
bool wasMVFHardForkPreviouslyActivated = false;

// track whether HF is active (MVHF-CORE-DES-TRIG-5)
bool isMVFHardForkActive = false;

// track whether auto wallet backup might still need to be done
// this is set to true at startup if client detects fork already triggered
// otherwise when the backup is made. (MVHF-CORE-DES-WABU-1)
bool fAutoBackupDone = false;

// default suffix to append to wallet filename for auto backup (MVHF-CORE-DES-WABU-1)
std::string autoWalletBackupSuffix = "auto.@.bak";

/** Add MVF-specific command line options (MVHF-CORE-DES-TRIG-8) */
std::string ForkCmdLineHelp()
{
    std::string strUsage;
    strUsage += HelpMessageGroup(_("Bitcoin MVF-Core Options:"));

    // automatic wallet backup parameters (MVHF-CORE-DES-WABU-1)
    strUsage += HelpMessageOpt("-autobackupwalletpath=<path>", _("Automatically backup the wallet to the autobackupwalletfile path after the block specified becomes the best block (-autobackupblock). Default: Enabled"));
    strUsage += HelpMessageOpt("-autobackupblock=<n>", _("Specify the block number that triggers the automatic wallet backup. Default: forkheight-1"));

    // fork height parameter (MVHF-CORE-DES-TRIG-1)
    strUsage += HelpMessageOpt("-forkheight=<n>", strprintf(_("Block height at which to fork on active network (integer). Defaults (also minimums): mainnet:%u,testnet=%u,regtest=%u"), (unsigned)HARDFORK_HEIGHT_MAINNET, (unsigned)HARDFORK_HEIGHT_TESTNET, (unsigned)HARDFORK_HEIGHT_REGTEST));

    // fork id (MVHF-CORE-DES-CSIG-1)
    strUsage += HelpMessageOpt("-forkid=<n>", strprintf(_("Fork id to use for signature change. Value must be between 0 and %d. Default is 0x%06x (%u)"), (unsigned)MAX_HARDFORK_SIGHASH_ID, (unsigned)HARDFORK_SIGHASH_ID, (unsigned)HARDFORK_SIGHASH_ID));

    return strUsage;
}

/** Performs fork-related setup / validation actions when the program starts */
void ForkSetup(const CChainParams& chainparams)
{
    int defaultForkHeightForNetwork = 0;
    std:string activeNetworkID = chainparams.NetworkIDString();

    LogPrintf("%s: MVF: doing setup\n", __func__);
    LogPrintf("%s: MVF: fork consensus code = %s\n", __func__, post_fork_consensus_id);
    LogPrintf("%s: MVF: active network = %s\n", __func__, activeNetworkID);

    // determine minimum fork height according to network
    // (these are set to the same as the default fork heights for now, but could be made different)
    if (activeNetworkID == CBaseChainParams::MAIN)
        defaultForkHeightForNetwork = HARDFORK_HEIGHT_MAINNET;
    else if (activeNetworkID == CBaseChainParams::TESTNET)
        defaultForkHeightForNetwork = HARDFORK_HEIGHT_TESTNET;
    else if (activeNetworkID == CBaseChainParams::REGTEST)
        defaultForkHeightForNetwork = HARDFORK_HEIGHT_REGTEST;
    else
        throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, activeNetworkID));

    FinalActivateForkHeight = GetArg("-forkheight", defaultForkHeightForNetwork);

    FinalForkId = GetArg("-forkid", HARDFORK_SIGHASH_ID);
    // check fork id for validity (MVHF-CORE-DES-CSIG-2)
    if (FinalForkId == 0) {
        LogPrintf("MVF: Warning: fork id = 0 will result in vulnerability to replay attacks\n");
    }
    else {
        if (FinalForkId < 0 || FinalForkId > MAX_HARDFORK_SIGHASH_ID) {
            LogPrintf("MVF: Error: specified fork id (%d) is not in range 0..%u\n", FinalForkId, (unsigned)MAX_HARDFORK_SIGHASH_ID);
            StartShutdown();
        }
    }

    if (GetBoolArg("-segwitfork", DEFAULT_TRIGGER_ON_SEGWIT))
        LogPrintf("%s: MVF: Segregated Witness trigger is ENABLED\n", __func__);
    else
        LogPrintf("%s: MVF: Segregated Witness trigger is DISABLED\n", __func__);

    LogPrintf("%s: MVF: active fork height = %d\n", __func__, FinalActivateForkHeight);

    LogPrintf("%s: MVF: active fork id = 0x%06x (%d)\n", __func__, FinalForkId, FinalForkId);

    if (GetBoolArg("-force-retarget", DEFAULT_FORCE_RETARGET))
        LogPrintf("%s: MVF: force-retarget is ENABLED\n", __func__);
    else
        LogPrintf("%s: MVF: force-retarget is DISABLED\n", __func__);

    LogPrintf("%s: MVF: auto backup block = %d\n", __func__, GetArg("-autobackupblock", FinalActivateForkHeight - 1));

    // check if btcfork.conf exists (MVHF-CORE-DES-TRIG-10)
    boost::filesystem::path pathBTCforkConfigFile(BTCFORK_CONF_FILENAME);
    if (!pathBTCforkConfigFile.is_complete())
        pathBTCforkConfigFile = GetDataDir(false) / pathBTCforkConfigFile;
    if (boost::filesystem::exists(pathBTCforkConfigFile)) {
        LogPrintf("%s: MVF: found marker config file at %s - client has already forked before\n", __func__, pathBTCforkConfigFile.string().c_str());
        wasMVFHardForkPreviouslyActivated = true;
    }
    else {
        LogPrintf("%s: MVF: no marker config file at %s - client has not forked yet\n", __func__, pathBTCforkConfigFile.string().c_str());
        wasMVFHardForkPreviouslyActivated = false;
    }

    // we should always set the activation flag to false during setup
    isMVFHardForkActive = false;
}

/** Actions when the fork triggers (MVHF-CORE-DES-TRIG-6) */
// doBackup parameter default is true
void ActivateFork(int actualForkHeight, bool doBackup)
{
    LogPrintf("%s: MVF: checking whether to perform fork activation\n", __func__);
    if (!isMVFHardForkActive && !wasMVFHardForkPreviouslyActivated)  // sanity check to protect the one-off actions
    {
        LogPrintf("%s: MVF: performing fork activation actions\n", __func__);

        // set so that we capture the actual height at which it forked
        // because this can be different from user-specified configuration
        // (e.g. soft-fork activated)
        FinalActivateForkHeight = actualForkHeight;

        boost::filesystem::path pathBTCforkConfigFile(BTCFORK_CONF_FILENAME);
        if (!pathBTCforkConfigFile.is_complete())
            pathBTCforkConfigFile = GetDataDir(false) / pathBTCforkConfigFile;

        LogPrintf("%s: MVF: checking for existence of %s\n", __func__, pathBTCforkConfigFile.string().c_str());

        // remove btcfork.conf if it already exists - it shall be overwritten
        if (boost::filesystem::exists(pathBTCforkConfigFile)) {
            LogPrintf("%s: MVF: removing %s\n", __func__, pathBTCforkConfigFile.string().c_str());
            try {
                boost::filesystem::remove(pathBTCforkConfigFile);
            } catch (const boost::filesystem::filesystem_error& e) {
                LogPrintf("%s: Unable to remove pidfile: %s\n", __func__, e.what());
            }
        }
        // try to write the btcfork.conf (MVHF-CORE-DES-TRIG-10)
        LogPrintf("%s: MVF: writing %s\n", __func__, pathBTCforkConfigFile.string().c_str());
        std::ofstream  btcforkfile(pathBTCforkConfigFile.string().c_str(), std::ios::out);
        btcforkfile << "forkheight=" << FinalActivateForkHeight << "\n";
        btcforkfile << "forkid=" << FinalForkId << "\n";

        LogPrintf("%s: MVF: active fork height = %d\n", __func__, FinalActivateForkHeight);
        LogPrintf("%s: MVF: active fork id = 0x%06x (%d)\n", __func__, FinalForkId, FinalForkId);

        // MVF-Core begin MVHF-CORE-DES-WABU-3
        // check if we need to do wallet auto backup at fork block
        // this is in case of soft-fork triggered activation
        // MVF-Core TODO: reduce code duplication between this block and main.cpp:UpdateTip()
        if (doBackup && !fAutoBackupDone)
        {
            std::string strWalletBackupFile = GetArg("-autobackupwalletpath", "");
            int BackupBlock = actualForkHeight;

            //LogPrintf("MVF DEBUG: autobackupwalletpath=%s\n",strWalletBackupFile);
            //LogPrintf("MVF DEBUG: autobackupblock=%d\n",BackupBlock);

            if (GetBoolArg("-disablewallet", false))
            {
                LogPrintf("MVF: -disablewallet and -autobackupwalletpath conflict so automatic backup disabled.");
                fAutoBackupDone = true;
            }
            else {
                // Auto Backup defined, but no need to check block height since
                // this is fork activation time and we still have not backed up
                // so just get on with it
                if (GetMainSignals().BackupWalletAuto(strWalletBackupFile, BackupBlock))
                    fAutoBackupDone = true;
                else {
                    // shutdown in case of wallet backup failure (MVHF-CORE-DES-WABU-5)
                    // MVF-Core TODO: investigate if this is safe in terms of wallet flushing/closing or if more needs to be done
                    btcforkfile << "error: unable to perform automatic backup - exiting" << "\n";
                    btcforkfile.close();
                    throw std::runtime_error("CWallet::BackupWalletAuto() : Auto wallet backup failed!");
                }
            }
            btcforkfile << "autobackupblock=" << FinalActivateForkHeight << "\n";
            LogPrintf("%s: MVF: soft-forked auto backup block = %d\n", __func__, FinalActivateForkHeight);

        }
        else {
            // auto backup was already made pre-fork - emit parameters
            btcforkfile << "autobackupblock=" << GetArg("-autobackupblock", FinalActivateForkHeight - 1) << "\n";
            LogPrintf("%s: MVF: height-based auto backup block = %d\n", __func__, GetArg("-autobackupblock", FinalActivateForkHeight - 1));
        }

        // close fork parameter file
        btcforkfile.close();
    }
    // set the flag so that other code knows HF is active
    LogPrintf("%s: MVF: enabling isMVFHardForkActive\n", __func__);
    isMVFHardForkActive = true;
}

/** Actions when the fork is deactivated in reorg (MVHF-CORE-DES-TRIG-7) */
void DeactivateFork(void)
{
    LogPrintf("%s: MVF: checking whether to perform fork deactivation\n", __func__);
    if (isMVFHardForkActive)
    {
        LogPrintf("%s: MVF: performing fork deactivation actions\n", __func__);
    }
    LogPrintf("%s: MVF: disabling isMVFHardForkActive\n", __func__);
    isMVFHardForkActive = false;
}
<|endoftext|>