<commit_before>//===-- LiveIntervals.cpp - Live Interval Analysis ------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the LiveInterval analysis pass which is used
// by the Linear Scan Register allocator. This pass linearizes the
// basic blocks of the function in DFS order and uses the
// LiveVariables pass to conservatively compute live intervals for
// each virtual and physical register.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "liveintervals"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/Function.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegInfo.h"
#include "llvm/Support/CFG.h"
#include "Support/Debug.h"
#include "Support/DepthFirstIterator.h"
#include "Support/Statistic.h"
#include <cmath>
#include <iostream>
#include <limits>

using namespace llvm;

namespace {
    RegisterAnalysis<LiveIntervals> X("liveintervals",
                                      "Live Interval Analysis");

    Statistic<> numIntervals("liveintervals", "Number of intervals");
};

void LiveIntervals::getAnalysisUsage(AnalysisUsage &AU) const
{
    AU.addPreserved<LiveVariables>();
    AU.addRequired<LiveVariables>();
    AU.addPreservedID(PHIEliminationID);
    AU.addRequiredID(PHIEliminationID);
    AU.addRequiredID(TwoAddressInstructionPassID);
    AU.addRequired<LoopInfo>();
    MachineFunctionPass::getAnalysisUsage(AU);
}

/// runOnMachineFunction - Register allocate the whole function
///
bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) {
    DEBUG(std::cerr << "Machine Function\n");
    mf_ = &fn;
    tm_ = &fn.getTarget();
    mri_ = tm_->getRegisterInfo();
    lv_ = &getAnalysis<LiveVariables>();
    allocatableRegisters_.clear();
    mbbi2mbbMap_.clear();
    mi2iMap_.clear();
    r2iMap_.clear();
    r2iMap_.clear();
    intervals_.clear();

    // mark allocatable registers
    allocatableRegisters_.resize(MRegisterInfo::FirstVirtualRegister);
    // Loop over all of the register classes...
    for (MRegisterInfo::regclass_iterator
             rci = mri_->regclass_begin(), rce = mri_->regclass_end();
         rci != rce; ++rci) {
        // Loop over all of the allocatable registers in the function...
        for (TargetRegisterClass::iterator
                 i = (*rci)->allocation_order_begin(*mf_),
                 e = (*rci)->allocation_order_end(*mf_); i != e; ++i) {
            allocatableRegisters_[*i] = true;  // The reg is allocatable!
        }
    }

    // number MachineInstrs
    unsigned miIndex = 0;
    for (MachineFunction::iterator mbb = mf_->begin(), mbbEnd = mf_->end();
         mbb != mbbEnd; ++mbb) {
        const std::pair<MachineBasicBlock*, unsigned>& entry =
            lv_->getMachineBasicBlockInfo(&*mbb);
        bool inserted = mbbi2mbbMap_.insert(std::make_pair(entry.second,
                                                           entry.first)).second;
        assert(inserted && "multiple index -> MachineBasicBlock");

        for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
             mi != miEnd; ++mi) {
            inserted = mi2iMap_.insert(std::make_pair(*mi, miIndex)).second;
            assert(inserted && "multiple MachineInstr -> index mappings");
            ++miIndex;
        }
    }

    computeIntervals();

    return true;
}

void LiveIntervals::printRegName(unsigned reg) const
{
    if (reg < MRegisterInfo::FirstVirtualRegister)
        std::cerr << mri_->getName(reg);
    else
        std::cerr << '%' << reg;
}

void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock* mbb,
                                             MachineBasicBlock::iterator mi,
                                             unsigned reg)
{
    DEBUG(std::cerr << "\t\t\tregister: ";printRegName(reg); std::cerr << '\n');

    unsigned instrIndex = getInstructionIndex(*mi);

    LiveVariables::VarInfo& vi = lv_->getVarInfo(reg);

    Interval* interval = 0;
    Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg);
    if (r2iit == r2iMap_.end()) {
        // add new interval
        intervals_.push_back(Interval(reg));
        // update interval index for this register
        r2iMap_[reg] = intervals_.size() - 1;
        interval = &intervals_.back();
    }
    else {
        interval = &intervals_[r2iit->second];
    }

    for (MbbIndex2MbbMap::iterator
             it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end();
         it != itEnd; ++it) {
        unsigned liveBlockIndex = it->first;
        MachineBasicBlock* liveBlock = it->second;
        if (liveBlockIndex < vi.AliveBlocks.size() &&
            vi.AliveBlocks[liveBlockIndex] &&
            !liveBlock->empty()) {
            unsigned start =  getInstructionIndex(liveBlock->front());
            unsigned end = getInstructionIndex(liveBlock->back()) + 1;
            interval->addRange(start, end);
        }
    }

    bool killedInDefiningBasicBlock = false;
    for (int i = 0, e = vi.Kills.size(); i != e; ++i) {
        MachineBasicBlock* killerBlock = vi.Kills[i].first;
        MachineInstr* killerInstr = vi.Kills[i].second;
        unsigned start = (mbb == killerBlock ?
                          instrIndex :
                          getInstructionIndex(killerBlock->front()));
        unsigned end = getInstructionIndex(killerInstr) + 1;
        if (start < end) {
            killedInDefiningBasicBlock |= mbb == killerBlock;
            interval->addRange(start, end);
        }
    }

    if (!killedInDefiningBasicBlock) {
        unsigned end = getInstructionIndex(mbb->back()) + 1;
        interval->addRange(instrIndex, end);
    }
}

void LiveIntervals::handlePhysicalRegisterDef(MachineBasicBlock* mbb,
                                              MachineBasicBlock::iterator mi,
                                              unsigned reg)
{
    DEBUG(std::cerr << "\t\t\tregister: ";printRegName(reg); std::cerr << '\n');
    if (!lv_->getAllocatablePhysicalRegisters()[reg]) {
        DEBUG(std::cerr << "\t\t\t\tnon allocatable register: ignoring\n");
        return;
    }

    unsigned start = getInstructionIndex(*mi);
    unsigned end = start;

    for (MachineBasicBlock::iterator e = mbb->end(); mi != e; ++mi) {
        for (LiveVariables::killed_iterator
                 ki = lv_->dead_begin(*mi),
                 ke = lv_->dead_end(*mi);
             ki != ke; ++ki) {
            if (reg == ki->second) {
                end = getInstructionIndex(ki->first) + 1;
                goto exit;
            }
        }

        for (LiveVariables::killed_iterator
                 ki = lv_->killed_begin(*mi),
                 ke = lv_->killed_end(*mi);
             ki != ke; ++ki) {
            if (reg == ki->second) {
                end = getInstructionIndex(ki->first) + 1;
                goto exit;
            }
        }
    }
exit:
    assert(start < end && "did not find end of interval?");

    Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg);
    if (r2iit != r2iMap_.end()) {
        unsigned ii = r2iit->second;
        Interval& interval = intervals_[ii];
        interval.addRange(start, end);
    }
    else {
        intervals_.push_back(Interval(reg));
        Interval& interval = intervals_.back();
        // update interval index for this register
        r2iMap_[reg] = intervals_.size() - 1;
        interval.addRange(start, end);
    }
}

void LiveIntervals::handleRegisterDef(MachineBasicBlock* mbb,
                                      MachineBasicBlock::iterator mi,
                                      unsigned reg)
{
    if (reg < MRegisterInfo::FirstVirtualRegister) {
        if (allocatableRegisters_[reg]) {
            handlePhysicalRegisterDef(mbb, mi, reg);
        }
    }
    else {
        handleVirtualRegisterDef(mbb, mi, reg);
    }
}

unsigned LiveIntervals::getInstructionIndex(MachineInstr* instr) const
{
    assert(mi2iMap_.find(instr) != mi2iMap_.end() &&
           "instruction not assigned a number");
    return mi2iMap_.find(instr)->second;
}

/// computeIntervals - computes the live intervals for virtual
/// registers. for some ordering of the machine instructions [1,N] a
/// live interval is an interval [i, j] where 1 <= i <= j <= N for
/// which a variable is live
void LiveIntervals::computeIntervals()
{
    DEBUG(std::cerr << "computing live intervals:\n");

    const LoopInfo& loopInfo = getAnalysis<LoopInfo>();

    for (MbbIndex2MbbMap::iterator
             it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end();
         it != itEnd; ++it) {
        MachineBasicBlock* mbb = it->second;
        DEBUG(std::cerr << "machine basic block: "
              << mbb->getBasicBlock()->getName() << "\n");

        unsigned loopDepth = loopInfo.getLoopDepth(mbb->getBasicBlock());

        for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
             mi != miEnd; ++mi) {
            MachineInstr* instr = *mi;
            const TargetInstrDescriptor& tid =
                tm_->getInstrInfo().get(instr->getOpcode());
            DEBUG(std::cerr << "\t\tinstruction["
                  << getInstructionIndex(instr) << "]: ";
                  instr->print(std::cerr, *tm_););

            // handle implicit defs
            for (const unsigned* id = tid.ImplicitDefs; *id; ++id) {
                unsigned physReg = *id;
                handlePhysicalRegisterDef(mbb, mi, physReg);
            }

            // handle explicit defs
            for (int i = instr->getNumOperands() - 1; i >= 0; --i) {
                MachineOperand& mop = instr->getOperand(i);

                if (!mop.isRegister())
                    continue;

                unsigned reg = mop.getAllocatedRegNum();
                // handle defs - build intervals
                if (mop.isDef()) {
                    if (reg < MRegisterInfo::FirstVirtualRegister)
                        handlePhysicalRegisterDef(mbb, mi, reg);
                    else
                        handleVirtualRegisterDef(mbb, mi, reg);
                }

                // update weights
                Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg);
                if (r2iit != r2iMap_.end() &&
                    reg >= MRegisterInfo::FirstVirtualRegister)
                    intervals_[r2iit->second].weight += pow(10.0F, loopDepth);
            }
        }
    }

    std::sort(intervals_.begin(), intervals_.end(), StartPointComp());
    DEBUG(std::copy(intervals_.begin(), intervals_.end(),
                    std::ostream_iterator<Interval>(std::cerr, "\n")));
}

LiveIntervals::Interval::Interval(unsigned r)
    : reg(r),
      weight((r < MRegisterInfo::FirstVirtualRegister ?
              std::numeric_limits<float>::max() : 0.0F))
{

}

void LiveIntervals::Interval::addRange(unsigned start, unsigned end)
{
    DEBUG(std::cerr << "\t\t\t\tadding range: [" << start <<','<< end << "]\n");
    //assert(start < end && "invalid range?");
    Range range = std::make_pair(start, end);
    Ranges::iterator it =
        ranges.insert(std::upper_bound(ranges.begin(), ranges.end(), range),
                      range);

    DEBUG(std::cerr << "\t\t\t\tbefore merge forward: " << *this << '\n');
    mergeRangesForward(it);
    DEBUG(std::cerr << "\t\t\t\tbefore merge backward: " << *this << '\n');
    mergeRangesBackward(it);
    DEBUG(std::cerr << "\t\t\t\tafter merging: " << *this << '\n');
}

void LiveIntervals::Interval::mergeRangesForward(Ranges::iterator it)
{
    for (Ranges::iterator next = it + 1;
         next != ranges.end() && it->second >= next->first; ) {
        it->second = std::max(it->second, next->second);
        next = ranges.erase(next);
    }
}

void LiveIntervals::Interval::mergeRangesBackward(Ranges::iterator it)
{
    for (Ranges::iterator prev = it - 1;
         it != ranges.begin() && it->first <= prev->second; ) {
        it->first = std::min(it->first, prev->first);
        it->second = std::max(it->second, prev->second);
        it = ranges.erase(prev);
        prev = it - 1;
    }
}

bool LiveIntervals::Interval::liveAt(unsigned index) const
{
    Ranges::const_iterator r = ranges.begin();
    while (r != ranges.end() && index < r->second) {
        if (index >= r->first)
            return true;
        ++r;
    }
    return false;
}

bool LiveIntervals::Interval::overlaps(const Interval& other) const
{
    std::vector<bool> bitMap(end(), false);
    for (Ranges::const_iterator r = ranges.begin(); r != ranges.end(); ++r) {
        for (unsigned i = r->first; i < r->second; ++i)
            bitMap[i] = true;
    }
    for (Ranges::const_iterator r = other.ranges.begin();
         r != other.ranges.end(); ++r) {
        for (unsigned i = r->first;
             i < r->second && i < bitMap.size(); ++i)
            if (bitMap[i])
                return true;
    }

    return false;
}

std::ostream& llvm::operator<<(std::ostream& os,
                               const LiveIntervals::Interval& li)
{
    os << "%reg" << li.reg << ',' << li.weight << " = ";
    for (LiveIntervals::Interval::Ranges::const_iterator
             i = li.ranges.begin(), e = li.ranges.end(); i != e; ++i) {
        os << "[" << i->first << "," << i->second << "]";
    }
    return os;
}
<commit_msg>Do a separate pass to compute spill weights because doing it inline with live intervals was missing registers that were used before they were defined (in the arbitrary order live intervals numbers instructions).<commit_after>//===-- LiveIntervals.cpp - Live Interval Analysis ------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the LiveInterval analysis pass which is used
// by the Linear Scan Register allocator. This pass linearizes the
// basic blocks of the function in DFS order and uses the
// LiveVariables pass to conservatively compute live intervals for
// each virtual and physical register.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "liveintervals"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/Function.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegInfo.h"
#include "llvm/Support/CFG.h"
#include "Support/Debug.h"
#include "Support/DepthFirstIterator.h"
#include "Support/Statistic.h"
#include <cmath>
#include <iostream>
#include <limits>

using namespace llvm;

namespace {
    RegisterAnalysis<LiveIntervals> X("liveintervals",
                                      "Live Interval Analysis");

    Statistic<> numIntervals("liveintervals", "Number of intervals");
};

void LiveIntervals::getAnalysisUsage(AnalysisUsage &AU) const
{
    AU.addPreserved<LiveVariables>();
    AU.addRequired<LiveVariables>();
    AU.addPreservedID(PHIEliminationID);
    AU.addRequiredID(PHIEliminationID);
    AU.addRequiredID(TwoAddressInstructionPassID);
    AU.addRequired<LoopInfo>();
    MachineFunctionPass::getAnalysisUsage(AU);
}

/// runOnMachineFunction - Register allocate the whole function
///
bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) {
    DEBUG(std::cerr << "Machine Function\n");
    mf_ = &fn;
    tm_ = &fn.getTarget();
    mri_ = tm_->getRegisterInfo();
    lv_ = &getAnalysis<LiveVariables>();
    allocatableRegisters_.clear();
    mbbi2mbbMap_.clear();
    mi2iMap_.clear();
    r2iMap_.clear();
    r2iMap_.clear();
    intervals_.clear();

    // mark allocatable registers
    allocatableRegisters_.resize(MRegisterInfo::FirstVirtualRegister);
    // Loop over all of the register classes...
    for (MRegisterInfo::regclass_iterator
             rci = mri_->regclass_begin(), rce = mri_->regclass_end();
         rci != rce; ++rci) {
        // Loop over all of the allocatable registers in the function...
        for (TargetRegisterClass::iterator
                 i = (*rci)->allocation_order_begin(*mf_),
                 e = (*rci)->allocation_order_end(*mf_); i != e; ++i) {
            allocatableRegisters_[*i] = true;  // The reg is allocatable!
        }
    }

    // number MachineInstrs
    unsigned miIndex = 0;
    for (MachineFunction::iterator mbb = mf_->begin(), mbbEnd = mf_->end();
         mbb != mbbEnd; ++mbb) {
        const std::pair<MachineBasicBlock*, unsigned>& entry =
            lv_->getMachineBasicBlockInfo(&*mbb);
        bool inserted = mbbi2mbbMap_.insert(std::make_pair(entry.second,
                                                           entry.first)).second;
        assert(inserted && "multiple index -> MachineBasicBlock");

        for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
             mi != miEnd; ++mi) {
            inserted = mi2iMap_.insert(std::make_pair(*mi, miIndex)).second;
            assert(inserted && "multiple MachineInstr -> index mappings");
            ++miIndex;
        }
    }

    computeIntervals();

    // compute spill weights
    const LoopInfo& loopInfo = getAnalysis<LoopInfo>();

    for (MbbIndex2MbbMap::iterator
             it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end();
         it != itEnd; ++it) {
        MachineBasicBlock* mbb = it->second;

        unsigned loopDepth = loopInfo.getLoopDepth(mbb->getBasicBlock());

        for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
             mi != miEnd; ++mi) {
            MachineInstr* instr = *mi;
            for (int i = instr->getNumOperands() - 1; i >= 0; --i) {
                MachineOperand& mop = instr->getOperand(i);

                if (!mop.isVirtualRegister())
                    continue;

                unsigned reg = mop.getAllocatedRegNum();
                Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg);
                assert(r2iit != r2iMap_.end());
                intervals_[r2iit->second].weight += pow(10.0F, loopDepth);
            }
        }
    }

    return true;
}

void LiveIntervals::printRegName(unsigned reg) const
{
    if (reg < MRegisterInfo::FirstVirtualRegister)
        std::cerr << mri_->getName(reg);
    else
        std::cerr << '%' << reg;
}

void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock* mbb,
                                             MachineBasicBlock::iterator mi,
                                             unsigned reg)
{
    DEBUG(std::cerr << "\t\t\tregister: ";printRegName(reg); std::cerr << '\n');

    unsigned instrIndex = getInstructionIndex(*mi);

    LiveVariables::VarInfo& vi = lv_->getVarInfo(reg);

    Interval* interval = 0;
    Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg);
    if (r2iit == r2iMap_.end()) {
        // add new interval
        intervals_.push_back(Interval(reg));
        // update interval index for this register
        r2iMap_[reg] = intervals_.size() - 1;
        interval = &intervals_.back();
    }
    else {
        interval = &intervals_[r2iit->second];
    }

    for (MbbIndex2MbbMap::iterator
             it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end();
         it != itEnd; ++it) {
        unsigned liveBlockIndex = it->first;
        MachineBasicBlock* liveBlock = it->second;
        if (liveBlockIndex < vi.AliveBlocks.size() &&
            vi.AliveBlocks[liveBlockIndex] &&
            !liveBlock->empty()) {
            unsigned start =  getInstructionIndex(liveBlock->front());
            unsigned end = getInstructionIndex(liveBlock->back()) + 1;
            interval->addRange(start, end);
        }
    }

    bool killedInDefiningBasicBlock = false;
    for (int i = 0, e = vi.Kills.size(); i != e; ++i) {
        MachineBasicBlock* killerBlock = vi.Kills[i].first;
        MachineInstr* killerInstr = vi.Kills[i].second;
        unsigned start = (mbb == killerBlock ?
                          instrIndex :
                          getInstructionIndex(killerBlock->front()));
        unsigned end = getInstructionIndex(killerInstr) + 1;
        if (start < end) {
            killedInDefiningBasicBlock |= mbb == killerBlock;
            interval->addRange(start, end);
        }
    }

    if (!killedInDefiningBasicBlock) {
        unsigned end = getInstructionIndex(mbb->back()) + 1;
        interval->addRange(instrIndex, end);
    }
}

void LiveIntervals::handlePhysicalRegisterDef(MachineBasicBlock* mbb,
                                              MachineBasicBlock::iterator mi,
                                              unsigned reg)
{
    DEBUG(std::cerr << "\t\t\tregister: ";printRegName(reg); std::cerr << '\n');
    if (!lv_->getAllocatablePhysicalRegisters()[reg]) {
        DEBUG(std::cerr << "\t\t\t\tnon allocatable register: ignoring\n");
        return;
    }

    unsigned start = getInstructionIndex(*mi);
    unsigned end = start;

    for (MachineBasicBlock::iterator e = mbb->end(); mi != e; ++mi) {
        for (LiveVariables::killed_iterator
                 ki = lv_->dead_begin(*mi),
                 ke = lv_->dead_end(*mi);
             ki != ke; ++ki) {
            if (reg == ki->second) {
                end = getInstructionIndex(ki->first) + 1;
                goto exit;
            }
        }

        for (LiveVariables::killed_iterator
                 ki = lv_->killed_begin(*mi),
                 ke = lv_->killed_end(*mi);
             ki != ke; ++ki) {
            if (reg == ki->second) {
                end = getInstructionIndex(ki->first) + 1;
                goto exit;
            }
        }
    }
exit:
    assert(start < end && "did not find end of interval?");

    Reg2IntervalMap::iterator r2iit = r2iMap_.find(reg);
    if (r2iit != r2iMap_.end()) {
        unsigned ii = r2iit->second;
        Interval& interval = intervals_[ii];
        interval.addRange(start, end);
    }
    else {
        intervals_.push_back(Interval(reg));
        Interval& interval = intervals_.back();
        // update interval index for this register
        r2iMap_[reg] = intervals_.size() - 1;
        interval.addRange(start, end);
    }
}

void LiveIntervals::handleRegisterDef(MachineBasicBlock* mbb,
                                      MachineBasicBlock::iterator mi,
                                      unsigned reg)
{
    if (reg < MRegisterInfo::FirstVirtualRegister) {
        if (allocatableRegisters_[reg]) {
            handlePhysicalRegisterDef(mbb, mi, reg);
        }
    }
    else {
        handleVirtualRegisterDef(mbb, mi, reg);
    }
}

unsigned LiveIntervals::getInstructionIndex(MachineInstr* instr) const
{
    assert(mi2iMap_.find(instr) != mi2iMap_.end() &&
           "instruction not assigned a number");
    return mi2iMap_.find(instr)->second;
}

/// computeIntervals - computes the live intervals for virtual
/// registers. for some ordering of the machine instructions [1,N] a
/// live interval is an interval [i, j] where 1 <= i <= j <= N for
/// which a variable is live
void LiveIntervals::computeIntervals()
{
    DEBUG(std::cerr << "computing live intervals:\n");

    for (MbbIndex2MbbMap::iterator
             it = mbbi2mbbMap_.begin(), itEnd = mbbi2mbbMap_.end();
         it != itEnd; ++it) {
        MachineBasicBlock* mbb = it->second;
        DEBUG(std::cerr << "machine basic block: "
              << mbb->getBasicBlock()->getName() << "\n");

        for (MachineBasicBlock::iterator mi = mbb->begin(), miEnd = mbb->end();
             mi != miEnd; ++mi) {
            MachineInstr* instr = *mi;
            const TargetInstrDescriptor& tid =
                tm_->getInstrInfo().get(instr->getOpcode());
            DEBUG(std::cerr << "\t\tinstruction["
                  << getInstructionIndex(instr) << "]: ";
                  instr->print(std::cerr, *tm_););

            // handle implicit defs
            for (const unsigned* id = tid.ImplicitDefs; *id; ++id) {
                unsigned physReg = *id;
                handlePhysicalRegisterDef(mbb, mi, physReg);
            }

            // handle explicit defs
            for (int i = instr->getNumOperands() - 1; i >= 0; --i) {
                MachineOperand& mop = instr->getOperand(i);

                if (!mop.isRegister())
                    continue;

                unsigned reg = mop.getAllocatedRegNum();
                // handle defs - build intervals
                if (mop.isDef()) {
                    if (reg < MRegisterInfo::FirstVirtualRegister)
                        handlePhysicalRegisterDef(mbb, mi, reg);
                    else
                        handleVirtualRegisterDef(mbb, mi, reg);
                }
            }
        }
    }

    std::sort(intervals_.begin(), intervals_.end(), StartPointComp());
    DEBUG(std::copy(intervals_.begin(), intervals_.end(),
                    std::ostream_iterator<Interval>(std::cerr, "\n")));
}

LiveIntervals::Interval::Interval(unsigned r)
    : reg(r),
      weight((r < MRegisterInfo::FirstVirtualRegister ?
              std::numeric_limits<float>::max() : 0.0F))
{

}

void LiveIntervals::Interval::addRange(unsigned start, unsigned end)
{
    DEBUG(std::cerr << "\t\t\t\tadding range: [" << start <<','<< end << "]\n");
    //assert(start < end && "invalid range?");
    Range range = std::make_pair(start, end);
    Ranges::iterator it =
        ranges.insert(std::upper_bound(ranges.begin(), ranges.end(), range),
                      range);

    DEBUG(std::cerr << "\t\t\t\tbefore merge forward: " << *this << '\n');
    mergeRangesForward(it);
    DEBUG(std::cerr << "\t\t\t\tbefore merge backward: " << *this << '\n');
    mergeRangesBackward(it);
    DEBUG(std::cerr << "\t\t\t\tafter merging: " << *this << '\n');
}

void LiveIntervals::Interval::mergeRangesForward(Ranges::iterator it)
{
    for (Ranges::iterator next = it + 1;
         next != ranges.end() && it->second >= next->first; ) {
        it->second = std::max(it->second, next->second);
        next = ranges.erase(next);
    }
}

void LiveIntervals::Interval::mergeRangesBackward(Ranges::iterator it)
{
    for (Ranges::iterator prev = it - 1;
         it != ranges.begin() && it->first <= prev->second; ) {
        it->first = std::min(it->first, prev->first);
        it->second = std::max(it->second, prev->second);
        it = ranges.erase(prev);
        prev = it - 1;
    }
}

bool LiveIntervals::Interval::liveAt(unsigned index) const
{
    Ranges::const_iterator r = ranges.begin();
    while (r != ranges.end() && index < r->second) {
        if (index >= r->first)
            return true;
        ++r;
    }
    return false;
}

bool LiveIntervals::Interval::overlaps(const Interval& other) const
{
    std::vector<bool> bitMap(end(), false);
    for (Ranges::const_iterator r = ranges.begin(); r != ranges.end(); ++r) {
        for (unsigned i = r->first; i < r->second; ++i)
            bitMap[i] = true;
    }
    for (Ranges::const_iterator r = other.ranges.begin();
         r != other.ranges.end(); ++r) {
        for (unsigned i = r->first;
             i < r->second && i < bitMap.size(); ++i)
            if (bitMap[i])
                return true;
    }

    return false;
}

std::ostream& llvm::operator<<(std::ostream& os,
                               const LiveIntervals::Interval& li)
{
    os << "%reg" << li.reg << ',' << li.weight << " = ";
    for (LiveIntervals::Interval::Ranges::const_iterator
             i = li.ranges.begin(), e = li.ranges.end(); i != e; ++i) {
        os << "[" << i->first << "," << i->second << "]";
    }
    return os;
}
<|endoftext|>


<commit_before>//C++ libs
#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <algorithm>

//C libs
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

const string cmd_delimiter = ";|&#";

void splice_input(queue<string> &cmds, queue<char> &conns, const string &input);
bool run_command(string &input, char &conn);
void tokenize(vector<char*> &comms, string &input);
void trim_lead_and_trail(string &str);

int main()
{
  string input;
  char logic;
  queue<string> commands;
  queue<char> connectors;
  bool running = true;

  char *hostname = new char[20];

  if(gethostname(hostname, 20) == -1)
  {
    perror("Error with getting hostname!");
  }

  //Continue prompting
  while(1)
  {
    cout << getlogin() << "@" << hostname << "$ ";

    getline(cin, input);
    splice_input(commands, connectors, input);

    //After getting input from the user begin dequeing
    //until the queue of commands is empty or logic
    //returns to stop running
    while(!commands.empty() && running)
    {
      //Get command from queue
      input = commands.front();
      commands.pop();
      //Get connector from queue
      if(!connectors.empty())
      {
        logic = connectors.front();
        connectors.pop();
      }

      //Check if input is exit
      //And begin handling command
      if(input.find("exit") == string::npos)
        running = run_command(input, logic);
      else
        exit(1);

      //Clear queues
      if(!running)
      {
        connectors = queue<char>();
        commands = queue<string>();
      }
    }
    //Reset running
    running = true;
  }

  return 0;
}

//Splits the commands and connectors into seperate queues.
void splice_input(queue<string> &cmds, queue<char> &conns, const string &input)
{
  int pos = 0;
  char logic;
  string new_cmd;
  string parse = input;

  while(pos != -1)
  {
    pos = parse.find_first_of(cmd_delimiter);
    new_cmd = parse.substr(0, pos);
    logic = parse[pos];

    trim_lead_and_trail(new_cmd);

    if(logic == '&' || logic == '|')
    {
      cmds.push(new_cmd);
      parse.erase(0, pos + 2);
    }
    else if(logic == ';')
    {
      cmds.push(new_cmd);
      parse.erase(0, pos + 1);
    }
    else
      cmds.push(new_cmd);

    if(logic == '#')
      return;

    conns.push(logic);
  }
}

bool run_command(string &input, char &conn)
{
  int pid = fork();
  vector<char*> tokens;
  int status = 0;

  if(pid == -1)
  {
    perror("Error with fork()");
    exit(1);
  }
  else if(pid == 0)
  {
    tokenize(tokens, input);
    char **cmds = &tokens[0];
    execvp(cmds[0], cmds);
    perror("Execvp failed!");
    exit(1);
  }
  else
  {
    wait(&status);

    //Deallocating memory
    for( size_t i = 0; i < tokens.size(); i++  )
      delete tokens[i];

    //Cleaning up vector
    tokens.clear();

    //Checking if the connector was AND
    if(conn == '&')
    {
      //If the previous cmd failed stop running
      if(status > 0)
        return false;
    }

    //Checking if the connector was OR
    if(conn == '|')
    {
      //No need to continue running since first cmd was true
      if(status <= 0)
        return false;
    }
  }

  //Continue getting commands
  return true;
}

void tokenize(vector<char*> &comms, string &input)
{
  string convert;
  string tokenizer = input;
  size_t pos = 0;

  trim_lead_and_trail(tokenizer);

  while(pos != string::npos )
  {
    pos = tokenizer.find(' ');
    convert = pos == string::npos ? tokenizer \
                                  : tokenizer.substr(0, pos);

    trim_lead_and_trail(convert);

    if(!convert.empty())
    {
      char *tmp = new char[convert.length() + 1];
      strcpy(tmp, convert.c_str());
      comms.push_back(tmp);
      tokenizer.erase(0, pos + 1);
    }
  }

  comms.push_back(NULL);

  return;
}

void trim_lead_and_trail(string &str)
{
  str.erase(str.begin(), std::find_if(str.begin(), str.end(), std::bind1st(std::not_equal_to<char>(), ' ')));
  str.erase(std::find_if(str.rbegin(), str.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), str.end());
}

<commit_msg>fixed single & and |<commit_after>//C++ libs
#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <algorithm>

//C libs
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

const string cmd_delimiter = ";|&#";

void splice_input(queue<string> &cmds, queue<char> &conns, const string &input);
bool run_command(string &input, char &conn);
void tokenize(vector<char*> &comms, string &input);
void trim_lead_and_trail(string &str);

int main()
{
  string input;
  char logic;
  queue<string> commands;
  queue<char> connectors;
  bool running = true;

  char *hostname = new char[20];

  if(gethostname(hostname, 20) == -1)
  {
    perror("Error with getting hostname!");
  }

  //Continue prompting
  while(1)
  {
    cout << getlogin() << "@" << hostname << "$ ";

    getline(cin, input);
    splice_input(commands, connectors, input);

    //After getting input from the user begin dequeing
    //until the queue of commands is empty or logic
    //returns to stop running
    while(!commands.empty() && running)
    {
      //Get command from queue
      input = commands.front();
      commands.pop();
      //Get connector from queue
      if(!connectors.empty())
      {
        logic = connectors.front();
        connectors.pop();
      }

      //Check if input is exit
      //And begin handling command
      if(input.find("exit") == string::npos)
        running = run_command(input, logic);
      else
        exit(1);

      //Clear queues
      if(!running)
      {
        connectors = queue<char>();
        commands = queue<string>();
      }
    }
    //Reset running
    running = true;
  }

  return 0;
}

//Splits the commands and connectors into seperate queues.
void splice_input(queue<string> &cmds, queue<char> &conns, const string &input)
{
  int pos = 0;
  char logic;
  string new_cmd;
  string parse = input;

  while(pos != -1)
  {
    pos = parse.find_first_of(cmd_delimiter);
    new_cmd = parse.substr(0, pos);
    logic = parse[pos];

    trim_lead_and_trail(new_cmd);

    if(logic == '&' || logic == '|')
    {
      if(parse[pos + 1] == logic)
        cmds.push(new_cmd);
      parse.erase(0, pos + 2);
    }
    else if(logic == ';')
    {
      if(parse[pos + 1] == logic)
        cmds.push(new_cmd);
      parse.erase(0, pos + 1);
    }
    else
      cmds.push(new_cmd);

    if(logic == '#')
      return;

    conns.push(logic);
  }
}

bool run_command(string &input, char &conn)
{
  int pid = fork();
  vector<char*> tokens;
  int status = 0;

  if(pid == -1)
  {
    perror("Error with fork()");
    exit(1);
  }
  else if(pid == 0)
  {
    tokenize(tokens, input);
    char **cmds = &tokens[0];
    execvp(cmds[0], cmds);
    perror("Execvp failed!");
    exit(1);
  }
  else
  {
    wait(&status);

    //Deallocating memory
    for( size_t i = 0; i < tokens.size(); i++  )
      delete tokens[i];

    //Cleaning up vector
    tokens.clear();

    //Checking if the connector was AND
    if(conn == '&')
    {
      //If the previous cmd failed stop running
      if(status > 0)
        return false;
    }

    //Checking if the connector was OR
    if(conn == '|')
    {
      //No need to continue running since first cmd was true
      if(status <= 0)
        return false;
    }
  }

  //Continue getting commands
  return true;
}

void tokenize(vector<char*> &comms, string &input)
{
  string convert;
  string tokenizer = input;
  size_t pos = 0;

  trim_lead_and_trail(tokenizer);

  while(pos != string::npos )
  {
    pos = tokenizer.find(' ');
    convert = pos == string::npos ? tokenizer \
                                  : tokenizer.substr(0, pos);

    trim_lead_and_trail(convert);

    if(!convert.empty())
    {
      char *tmp = new char[convert.length() + 1];
      strcpy(tmp, convert.c_str());
      comms.push_back(tmp);
      tokenizer.erase(0, pos + 1);
    }
  }

  comms.push_back(NULL);

  return;
}

void trim_lead_and_trail(string &str)
{
  str.erase(str.begin(), std::find_if(str.begin(), str.end(), std::bind1st(std::not_equal_to<char>(), ' ')));
  str.erase(std::find_if(str.rbegin(), str.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), str.end());
}

<|endoftext|>


<commit_before>#include "client_manager.hh"

#include "buffer_manager.hh"
#include "color_registry.hh"
#include "command_manager.hh"
#include "event_manager.hh"
#include "file.hh"
#include "user_interface.hh"
#include "window.hh"

namespace Kakoune
{

struct ClientManager::Client
{
    Client(std::unique_ptr<UserInterface>&& ui, Window& window,
           String name)
        : user_interface(std::move(ui)),
          input_handler(*user_interface),
          name(std::move(name))
    {
        kak_assert(not this->name.empty());
        context().change_editor(window);
    }
    Client(Client&&) = delete;
    Client& operator=(Client&& other) = delete;

    Context& context() { return input_handler.context(); }

    std::unique_ptr<UserInterface> user_interface;
    InputHandler  input_handler;
    String        name;
};

ClientManager::ClientManager() = default;
ClientManager::~ClientManager() = default;

String ClientManager::generate_name() const
{
    for (int i = 0; true; ++i)
    {
        String name = "unnamed" + int_to_str(i);
        bool found = false;
        for (auto& client : m_clients)
        {
            if (client->name == name)
            {
                found = true;
                break;
            }
        }
        if (not found)
            return name;
    }
}

void ClientManager::create_client(std::unique_ptr<UserInterface>&& ui,
                                  const String& init_commands)
{
    Buffer& buffer = **BufferManager::instance().begin();
    m_clients.emplace_back(new Client{std::move(ui), get_unused_window_for_buffer(buffer),
                                      generate_name()});
    Context*       context = &m_clients.back()->context();
    try
    {
        CommandManager::instance().execute(init_commands, *context);
    }
    catch (Kakoune::runtime_error& error)
    {
        context->print_status({ error.description(), get_color("Error") });
        context->hooks().run_hook("RuntimeError", error.description(), *context);
    }
    catch (Kakoune::client_removed&)
    {
        m_clients.pop_back();
        return;
    }

    context->ui().set_input_callback([context, this]() {
        try
        {
            context->input_handler().handle_available_inputs();
            context->window().forget_timestamp();
        }
        catch (Kakoune::runtime_error& error)
        {
            context->print_status({ error.description(), get_color("Error") });
            context->hooks().run_hook("RuntimeError", error.description(), *context);
        }
        catch (Kakoune::client_removed&)
        {
            ClientManager::instance().remove_client_by_context(*context);
        }
        ClientManager::instance().redraw_clients();
    });
    redraw_clients();
}

void ClientManager::remove_client_by_context(Context& context)
{
    for (auto it = m_clients.begin(); it != m_clients.end(); ++it)
    {
        if (&(*it)->context() == &context)
        {
             m_clients.erase(it);
             return;
        }
    }
    kak_assert(false);
}

Window& ClientManager::get_unused_window_for_buffer(Buffer& buffer)
{
    for (auto& w : m_windows)
    {
        if (&w->buffer() != &buffer)
           continue;

        auto it = std::find_if(m_clients.begin(), m_clients.end(),
                               [&](const std::unique_ptr<Client>& client)
                               { return &client->context().window() == w.get(); });
        if (it == m_clients.end())
        {
            w->forget_timestamp();
            return *w;
        }
    }
    m_windows.emplace_back(new Window(buffer));
    return *m_windows.back();
}

void ClientManager::ensure_no_client_uses_buffer(Buffer& buffer)
{
    for (auto& client : m_clients)
    {
        client->context().forget_jumps_to_buffer(buffer);

        if (&client->context().buffer() != &buffer)
            continue;

        if (client->context().editor().is_editing())
            throw runtime_error("client '" + client->name + "' is inserting in '" +
                                buffer.display_name() + '\'');

        // change client context to edit the first buffer which is not the
        // specified one. As BufferManager stores buffer according to last
        // access, this selects a sensible buffer to display.
        for (auto& buf : BufferManager::instance())
        {
            if (buf != &buffer)
            {
               Window& w = get_unused_window_for_buffer(*buf);
               client->context().change_editor(w);
               break;
            }
        }
    }
    auto end = std::remove_if(m_windows.begin(), m_windows.end(),
                              [&buffer](const std::unique_ptr<Window>& w)
                              { return &w->buffer() == &buffer; });
    m_windows.erase(end, m_windows.end());
}

void ClientManager::set_client_name(Context& context, String name)
{
    auto it = find_if(m_clients, [&name](std::unique_ptr<Client>& client)
                                 { return client->name == name; });
    if (it != m_clients.end() and &(*it)->context() != &context)
        throw runtime_error("name not unique: " + name);

    for (auto& client : m_clients)
    {
        if (&client->context() == &context)
        {
            client->name = std::move(name);
            return;
        }
    }
    throw runtime_error("no client for current context");
}

String ClientManager::get_client_name(const Context& context)
{
    for (auto& client : m_clients)
    {
        if (&client->context() == &context)
            return client->name;
    }
    throw runtime_error("no client for current context");
}

Context& ClientManager::get_client_context(const String& name)
{
    auto it = find_if(m_clients, [&name](std::unique_ptr<Client>& client)
                                 { return client->name == name; });
    if (it != m_clients.end())
        return (*it)->context();
    throw runtime_error("no client named: " + name);
}

static DisplayLine generate_status_line(const Context& context)
{
    BufferCoord cursor = context.editor().main_selection().last().coord();
    std::ostringstream oss;

    oss << context.buffer().display_name()
        << " " << (int)cursor.line+1 << "," << (int)cursor.column+1;
    if (context.buffer().is_modified())
        oss << " [+]";
    if (context.input_handler().is_recording())
       oss << " [recording]";
    if (context.buffer().flags() & Buffer::Flags::New)
        oss << " [new file]";
    oss << " [" << context.editor().selections().size() << " sel]";
    if (context.editor().is_editing())
        oss << " [insert]";
    return { oss.str(), get_color("StatusLine") };
}

void ClientManager::redraw_clients() const
{
    for (auto& client : m_clients)
    {
        Context& context = client->context();
        if (context.window().timestamp() != context.buffer().timestamp())
        {
            DisplayCoord dimensions = context.ui().dimensions();
            if (dimensions == DisplayCoord{0,0})
                return;
            context.window().set_dimensions(dimensions);
            context.window().update_display_buffer();;

            context.ui().draw(context.window().display_buffer(),
                              generate_status_line(context));
        }
    }
}

}
<commit_msg>display character column instead of byte column in status line<commit_after>#include "client_manager.hh"

#include "buffer_manager.hh"
#include "color_registry.hh"
#include "command_manager.hh"
#include "event_manager.hh"
#include "file.hh"
#include "user_interface.hh"
#include "window.hh"

namespace Kakoune
{

struct ClientManager::Client
{
    Client(std::unique_ptr<UserInterface>&& ui, Window& window,
           String name)
        : user_interface(std::move(ui)),
          input_handler(*user_interface),
          name(std::move(name))
    {
        kak_assert(not this->name.empty());
        context().change_editor(window);
    }
    Client(Client&&) = delete;
    Client& operator=(Client&& other) = delete;

    Context& context() { return input_handler.context(); }

    std::unique_ptr<UserInterface> user_interface;
    InputHandler  input_handler;
    String        name;
};

ClientManager::ClientManager() = default;
ClientManager::~ClientManager() = default;

String ClientManager::generate_name() const
{
    for (int i = 0; true; ++i)
    {
        String name = "unnamed" + int_to_str(i);
        bool found = false;
        for (auto& client : m_clients)
        {
            if (client->name == name)
            {
                found = true;
                break;
            }
        }
        if (not found)
            return name;
    }
}

void ClientManager::create_client(std::unique_ptr<UserInterface>&& ui,
                                  const String& init_commands)
{
    Buffer& buffer = **BufferManager::instance().begin();
    m_clients.emplace_back(new Client{std::move(ui), get_unused_window_for_buffer(buffer),
                                      generate_name()});
    Context*       context = &m_clients.back()->context();
    try
    {
        CommandManager::instance().execute(init_commands, *context);
    }
    catch (Kakoune::runtime_error& error)
    {
        context->print_status({ error.description(), get_color("Error") });
        context->hooks().run_hook("RuntimeError", error.description(), *context);
    }
    catch (Kakoune::client_removed&)
    {
        m_clients.pop_back();
        return;
    }

    context->ui().set_input_callback([context, this]() {
        try
        {
            context->input_handler().handle_available_inputs();
            context->window().forget_timestamp();
        }
        catch (Kakoune::runtime_error& error)
        {
            context->print_status({ error.description(), get_color("Error") });
            context->hooks().run_hook("RuntimeError", error.description(), *context);
        }
        catch (Kakoune::client_removed&)
        {
            ClientManager::instance().remove_client_by_context(*context);
        }
        ClientManager::instance().redraw_clients();
    });
    redraw_clients();
}

void ClientManager::remove_client_by_context(Context& context)
{
    for (auto it = m_clients.begin(); it != m_clients.end(); ++it)
    {
        if (&(*it)->context() == &context)
        {
             m_clients.erase(it);
             return;
        }
    }
    kak_assert(false);
}

Window& ClientManager::get_unused_window_for_buffer(Buffer& buffer)
{
    for (auto& w : m_windows)
    {
        if (&w->buffer() != &buffer)
           continue;

        auto it = std::find_if(m_clients.begin(), m_clients.end(),
                               [&](const std::unique_ptr<Client>& client)
                               { return &client->context().window() == w.get(); });
        if (it == m_clients.end())
        {
            w->forget_timestamp();
            return *w;
        }
    }
    m_windows.emplace_back(new Window(buffer));
    return *m_windows.back();
}

void ClientManager::ensure_no_client_uses_buffer(Buffer& buffer)
{
    for (auto& client : m_clients)
    {
        client->context().forget_jumps_to_buffer(buffer);

        if (&client->context().buffer() != &buffer)
            continue;

        if (client->context().editor().is_editing())
            throw runtime_error("client '" + client->name + "' is inserting in '" +
                                buffer.display_name() + '\'');

        // change client context to edit the first buffer which is not the
        // specified one. As BufferManager stores buffer according to last
        // access, this selects a sensible buffer to display.
        for (auto& buf : BufferManager::instance())
        {
            if (buf != &buffer)
            {
               Window& w = get_unused_window_for_buffer(*buf);
               client->context().change_editor(w);
               break;
            }
        }
    }
    auto end = std::remove_if(m_windows.begin(), m_windows.end(),
                              [&buffer](const std::unique_ptr<Window>& w)
                              { return &w->buffer() == &buffer; });
    m_windows.erase(end, m_windows.end());
}

void ClientManager::set_client_name(Context& context, String name)
{
    auto it = find_if(m_clients, [&name](std::unique_ptr<Client>& client)
                                 { return client->name == name; });
    if (it != m_clients.end() and &(*it)->context() != &context)
        throw runtime_error("name not unique: " + name);

    for (auto& client : m_clients)
    {
        if (&client->context() == &context)
        {
            client->name = std::move(name);
            return;
        }
    }
    throw runtime_error("no client for current context");
}

String ClientManager::get_client_name(const Context& context)
{
    for (auto& client : m_clients)
    {
        if (&client->context() == &context)
            return client->name;
    }
    throw runtime_error("no client for current context");
}

Context& ClientManager::get_client_context(const String& name)
{
    auto it = find_if(m_clients, [&name](std::unique_ptr<Client>& client)
                                 { return client->name == name; });
    if (it != m_clients.end())
        return (*it)->context();
    throw runtime_error("no client named: " + name);
}

static DisplayLine generate_status_line(const Context& context)
{
    auto pos = context.editor().main_selection().last();
    auto col = utf8::distance(context.buffer().iterator_at_line_begin(pos), pos);

    std::ostringstream oss;
    oss << context.buffer().display_name()
        << " " << (int)pos.line()+1 << "," << (int)col+1;
    if (context.buffer().is_modified())
        oss << " [+]";
    if (context.input_handler().is_recording())
       oss << " [recording]";
    if (context.buffer().flags() & Buffer::Flags::New)
        oss << " [new file]";
    oss << " [" << context.editor().selections().size() << " sel]";
    if (context.editor().is_editing())
        oss << " [insert]";
    return { oss.str(), get_color("StatusLine") };
}

void ClientManager::redraw_clients() const
{
    for (auto& client : m_clients)
    {
        Context& context = client->context();
        if (context.window().timestamp() != context.buffer().timestamp())
        {
            DisplayCoord dimensions = context.ui().dimensions();
            if (dimensions == DisplayCoord{0,0})
                return;
            context.window().set_dimensions(dimensions);
            context.window().update_display_buffer();;

            context.ui().draw(context.window().display_buffer(),
                              generate_status_line(context));
        }
    }
}

}
<|endoftext|>


<commit_before>#include "logreader.h"

Logreader::Logreader(QString filename, QString address, quint16 port){
    if (address == "127.0.0.1") {
        this->address = new QHostAddress(QHostAddress::LocalHost);
    } else {
        this->address = new QHostAddress(address);
    }
    this->port = port;
    this->log = new QFile(filename);

    if (this->log->open(QIODevice::ReadOnly)) {
        qDebug() << "File: " << filename << "successfuly opened." << "\n";
    } else {
        qDebug() << "Opening file" << filename << "failed." << "\n";
    }
}

Logreader::Logreader(QString filename, QHostAddress address, quint16 port){
    this->address = &address;
    this->port = port;

    this->log = new QFile(filename);

    if (this->log->open(QIODevice::ReadOnly)) {
        qDebug() << "File: " << filename << "successfuly opened." << "\n";
    } else {
        qDebug() << "Opening file" << filename << "failed." << "\n";
    }
}

QString Logreader::getLine(){
    return this->line;
}

int Logreader::readAndTransmit(){
    QString fileLine;
    QString parsedFileLine;
    fileLine = readDataFromFile();
    parsedFileLine = parseData(fileLine);
    //transmitData(parsedFileLine);
    qDebug() << parsedFileLine;
    qDebug() << counter;
    qDebug() << packetno;
    counter++;
    if (counter==2){
          packetno ++;
          counter = 0;
        }
    if (packetno > 2){
          packetno = 0;
    }
    return 0;
}

QString Logreader::readDataFromFile(){
    QString fileLine;
    if ((log->isReadable()) && (!log->atEnd())){
        fileLine = this->log->readLine();
    } else if (!log->isReadable()) {
        qDebug() << "File " << this->filename << " is not readable.\n";
    } else if (log->atEnd()) {
        log->seek(0);
    }
    return fileLine;
}

QString Logreader::parseData(QString fileLine){
    QList<QString> parsingData;
    QString parsedFileLine;
    QString processData;

    processData.clear();
    parsingData.clear();
    parsedFileLine.clear();

    foreach (QChar var, fileLine) {
        if (var != ';'){
            processData.append(var);
        } else if (var == ';'){
            parsingData.append(processData);
            processData.clear();
        }
    }

    // Chain for transmission assembly
    // TODO: Complete the parsed string and include a clause which will change the string to a status once in a while.
    if (!parsingData.isEmpty()) {
        switch (packetno){
        case 0:parsedFileLine.append("$MSG,");
               parsedFileLine.append("LAT");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(0));
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(1));
               parsedFileLine.append(',');
               parsedFileLine.append("LON");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(2));
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(3));
               parsedFileLine.append('*');
               parsedFileLine.append(checksum(parsedFileLine));
               parsedFileLine.append('\r');
               parsedFileLine.append('\n'); break;
        case 1:parsedFileLine.append("$MSG,");
               parsedFileLine.append("VLC");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(5));
               parsedFileLine.append(',');
               parsedFileLine.append("ENG");
               parsedFileLine.append("LS");
               parsedFileLine.append(',');
               parsedFileLine.append("xxx");
               parsedFileLine.append(',');
               parsedFileLine.append("ACX");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(6));
               parsedFileLine.append(',');
               parsedFileLine.append("ACY");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(7));
               parsedFileLine.append(',');
               parsedFileLine.append("ACZ");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(8));
               parsedFileLine.append('*');
               parsedFileLine.append(checksum(parsedFileLine));
               parsedFileLine.append('\r');
               parsedFileLine.append('\n'); break;
        case 2:parsedFileLine.append("$MSG,");
               parsedFileLine.append("HDG");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(4));
               parsedFileLine.append(',');
               parsedFileLine.append("HDT");
               parsedFileLine.append(',');
               parsedFileLine.append("xxx");
               parsedFileLine.append(',');
               parsedFileLine.append("ACP");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(9));
               parsedFileLine.append(',');
               parsedFileLine.append("ACW");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(10));
               parsedFileLine.append(',');
               parsedFileLine.append("ACR");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(11));
               parsedFileLine.append('*');
               parsedFileLine.append(checksum(parsedFileLine));
               parsedFileLine.append('\r');
               parsedFileLine.append('\n'); break;
        default: parsedFileLine.append("error");
        }
    }

    return parsedFileLine;
}

void Logreader::transmitData(QString inString){
    transmitter.writeDatagram(inString.toLatin1(), *this->address, port);
}

QString Logreader::checksum(QByteArray inData){
    QString table = "0123456789ABCDEF";
    char result[2];
    QString outChecksum;

    unsigned char checksum = 0x00;

    for (int i = 1; i < inData.length()-1; i++) {
        if (inData.at(i)=='*') {
            break;
        }
        checksum ^= (unsigned char) inData.at(i);
    }

    result[1] = table.at(checksum&0x0F).toLatin1();
    result[0] = table.at((checksum>>4)&0x0F).toLatin1();
    outChecksum.insert(0,result[0]);
    outChecksum.insert(1,result[1]);
    return outChecksum;
}

QString Logreader::checksum(QString inData){
    return checksum(inData.toLatin1());
}
<commit_msg>edited sentences such that it can read the last data of each line<commit_after>#include "logreader.h"

Logreader::Logreader(QString filename, QString address, quint16 port){
    if (address == "127.0.0.1") {
        this->address = new QHostAddress(QHostAddress::LocalHost);
    } else {
        this->address = new QHostAddress(address);
    }
    this->port = port;
    this->log = new QFile(filename);

    if (this->log->open(QIODevice::ReadOnly)) {
        qDebug() << "File: " << filename << "successfuly opened." << "\n";
    } else {
        qDebug() << "Opening file" << filename << "failed." << "\n";
    }
}

Logreader::Logreader(QString filename, QHostAddress address, quint16 port){
    this->address = &address;
    this->port = port;

    this->log = new QFile(filename);

    if (this->log->open(QIODevice::ReadOnly)) {
        qDebug() << "File: " << filename << "successfuly opened." << "\n";
    } else {
        qDebug() << "Opening file" << filename << "failed." << "\n";
    }
}

QString Logreader::getLine(){
    return this->line;
}

int Logreader::readAndTransmit(){
    QString fileLine;
    QString parsedFileLine;
    fileLine = readDataFromFile();
    parsedFileLine = parseData(fileLine);
    transmitData(parsedFileLine);
    qDebug() << parsedFileLine;
    counter++;
    if (counter==2){
          packetno ++;
          counter = 0;
        }
    if (packetno > 2){
          packetno = 0;
    }
    return 0;
}

QString Logreader::readDataFromFile(){
    QString fileLine;
    if ((log->isReadable()) && (!log->atEnd())){
        fileLine = this->log->readLine();
    } else if (!log->isReadable()) {
        qDebug() << "File " << this->filename << " is not readable.\n";
    } else if (log->atEnd()) {
        log->seek(0);
    }
    return fileLine;
}

QString Logreader::parseData(QString fileLine){
    QList<QString> parsingData;
    QString parsedFileLine;
    QString processData;

    processData.clear();
    parsingData.clear();
    parsedFileLine.clear();

    foreach (QChar var, fileLine) {
        if ((var != ';')&& (var != '\n')){
            processData.append(var);
        } else if ((var == ';')|| (var == '\n')){
            parsingData.append(processData);
            processData.clear();
        }
    }

    // Chain for transmission assembly
    // TODO: Complete the parsed string and include a clause which will change the string to a status once in a while.
    if (!parsingData.isEmpty()) {
        switch (packetno){
        case 0:parsedFileLine.append("$MSG,");
               parsedFileLine.append("LAT");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(0));
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(1));
               parsedFileLine.append(',');
               parsedFileLine.append("LON");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(2));
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(3));
               parsedFileLine.append('*');
               parsedFileLine.append(checksum(parsedFileLine));
               parsedFileLine.append('\r');
               parsedFileLine.append('\n'); break;
        case 1:parsedFileLine.append("$MSG,");
               parsedFileLine.append("VLC");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(5));
               parsedFileLine.append(',');
               parsedFileLine.append("ENG");
               parsedFileLine.append("LS");
               parsedFileLine.append(',');
               parsedFileLine.append("xxx");
               parsedFileLine.append(',');
               parsedFileLine.append("ACX");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(6));
               parsedFileLine.append(',');
               parsedFileLine.append("ACY");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(7));
               parsedFileLine.append(',');
               parsedFileLine.append("ACZ");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(8));
               parsedFileLine.append('*');
               parsedFileLine.append(checksum(parsedFileLine));
               parsedFileLine.append('\r');
               parsedFileLine.append('\n'); break;
        case 2:parsedFileLine.append("$MSG,");
               parsedFileLine.append("HDG");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(4));
               parsedFileLine.append(',');
               parsedFileLine.append("HDT");
               parsedFileLine.append(',');
               parsedFileLine.append("xxx");
               parsedFileLine.append(',');
               parsedFileLine.append("ACP");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(9));
               parsedFileLine.append(',');
               parsedFileLine.append("ACW");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(10));
               parsedFileLine.append(',');
               parsedFileLine.append("ACR");
               parsedFileLine.append(',');
               parsedFileLine.append(parsingData.at(11));
               parsedFileLine.append('*');
               parsedFileLine.append(checksum(parsedFileLine));
               parsedFileLine.append('\r');
               parsedFileLine.append('\n'); break;
        default: parsedFileLine.append("error");
        }
    }

    return parsedFileLine;
}

void Logreader::transmitData(QString inString){
    transmitter.writeDatagram(inString.toLatin1(), *this->address, port);
}

QString Logreader::checksum(QByteArray inData){
    QString table = "0123456789ABCDEF";
    char result[2];
    QString outChecksum;

    unsigned char checksum = 0x00;

    for (int i = 1; i < inData.length()-1; i++) {
        if (inData.at(i)=='*') {
            break;
        }
        checksum ^= (unsigned char) inData.at(i);
    }

    result[1] = table.at(checksum&0x0F).toLatin1();
    result[0] = table.at((checksum>>4)&0x0F).toLatin1();
    outChecksum.insert(0,result[0]);
    outChecksum.insert(1,result[1]);
    return outChecksum;
}

QString Logreader::checksum(QString inData){
    return checksum(inData.toLatin1());
}
<|endoftext|>


<commit_before>/**
 * @file csv.cpp
 * @brief CSV file handling.
 *
 * Usage:
 * csv$make takes a settings hash, and produces a CSV object.
 * csv$line handles a line in the CSV, typically read from a file,
 *     and returns a hash, list or none (if header or skip line
 *     was fed in).
 * csv$cols returns the columns list.
 *
 * Make hash parameters:
 *   `columns is a list of column names, which implies the csv has no header
 *   `list if true forces the output to be lists
 *   `nohead ignores the header even if no col names are given
 *           (names will be invented if the output is a hash)
 *   `skip defines a number of lines to ignore at the start
 *   `delimiter sets a delimiting character
 *   `types sets a column type string consisting of the chars "i",
 *          "f" or "s" (int,float,string). If only one char is
 *          provided, it's used for all cols. Otherwise the char
 *          used is types[colname%strlen(types)]
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>

#include <angort/angort.h>

#include "../hashgets.h"
#include "../wrappers.h"

using namespace angort;

// clear a string list and free all its strings
inline void clearList(ArrayList<char *> *l){
    ArrayListIterator<char*> iter(l);
    for(iter.first();!iter.isDone();iter.next()){
        free(*iter.current());
    }
    l->clear();
}

// temp list used for each line
static ArrayList<char*> list;

// add a new string to the list (takes a length because the list
// may not be null-terminated
void addToList(ArrayList<char *> *l,const char *s,int len){
    char **newfield = l->append();
    char *newstr = (char *)malloc(len+1);
    *newfield = newstr;
    memcpy(newstr,s,len);
    newstr[len]=0;
}

// split a null-terminated line, which must not end in \n.
// If at maxcols, delimiters are ignored.
static ArrayList<char*> *splitLine(const char *s,const char delim,int maxCols=0){
    // we add characters to this as we build up fields, it's
    // the easiest way to do quoting and escaping.
    char *fbuf=(char *)alloca(strlen(s));

    // static list of fields, reused for each line

    clearList(&list);
    // if non-zero, we are in a quoted field
    char quotechar = 0;
    int cols=0;
    char *fptr=fbuf; // field start ptr
    for(;;) {
        // two clauses here:
        // first says "if we're at the last column and the end,
        // fill in the last column." Second says "if columns are free,
        // or we're at or before the second to last column, and there's
        // and end or unquoted delimiter." If either are true, add.
        if(((cols==maxCols-1) && *s==0) || (
              (maxCols==0 || cols<(maxCols-1) ) &&
              (*s==0 || (*s==delim && !quotechar)))){
            // delimiter found, and not in quoted field, and not
            // at maxcolumns. Add string.
            addToList(&list,fbuf,fptr-fbuf);
            cols++;
            fptr=fbuf; // restart field buffer
        } else if(quotechar && *s==quotechar){
            // end of quote
            quotechar=0;
        } else if(*s=='\'' || *s == '\"'){
            // start of quote
            quotechar = *s;
        } else if(*s=='\\') {
            // escape char
            *fptr++ = *++s;
        } else {
            // ordinary char, add to buffer
            *fptr++ = *s;
        }

        if(*s==0)break;
        s++;
    }
    return &list;
}

class CSV : public GarbageCollected {
    int numCols;
    const char **colNames;
    bool noHead;
    int skipLines;
    bool createList;
    char delim;
    // if true, holds a string of column type chars. These are
    // s=str,f=float,i=int. If missing, all cols are strings.
    // If too short, is modded over i.e. so that a single "f" means all
    // cols are float.
    const char *types;
    int numTypes; // only valid if above is nonnull
    // the actual data, PER LINE. It's either a hash or a list.
    Value linev;

public:
    CSV(Hash *h){ // settings hash
        Value *v;
        colNames=NULL;
        if((v=h->getSym("columns"))!=NULL){
            // predefined column headers override those in the file
            ArrayList<Value> *l = Types::tList->get(v);
            numCols = l->count();
            colNames = new const char *[numCols];
            ArrayListIterator<Value> iter(l);
            int i=0;
            for(iter.first();!iter.isDone();iter.next()){
                colNames[i++] = strdup(iter.current()->toString().get());
            }

        }
        // do we consider the first line to be just data?
        noHead = hgetintdef(h,"nohead",0)!=0;

        // how many lines at the start do we skip?
        skipLines = hgetintdef(h,"skip",0);

        // do we create a hash for each line, or will a list do?
        createList = hgetintdef(h,"list",0)!=0;

        // delimiter
        delim = hgetstrdef(h,"delimiter",",")[0];

        // types
        types = hgetstrdef(h,"types",NULL);
        if(types && !*types)types=NULL; // don't allow empty str.
        if(types){
            types=strdup(types);
            numTypes = strlen(types);
        }
    }

    virtual ~CSV(){
        printf("Destuctor\n");
        if(colNames)
            delete colNames;
        if(types)
            free((void *)types);
    }

    // process a line of input and set the value accordingly
    void line(Value *linev,const char *s){
        // are we skipping?
        if(skipLines--){
            linev->clr();
        }

        if(!colNames && noHead){
            // no colnames and no head! We'll have to invent something.
            // we end up doing this twice, but it's only on the first line
            ArrayList<char *> *l = splitLine(s,delim,numCols);
            numCols = l->count();
            colNames = new const char *[numCols];
            for(int i=0;i<numCols;i++){
                char buf[256];
                sprintf(buf,"V%d",i);
                colNames[i]=strdup(buf);
            }
        }

        if(!colNames){ // no col names, but we are allowed a header
            //no, extract them
            ArrayList<char *> *l = splitLine(s,delim,0);
            numCols = l->count();
            colNames = new const char *[numCols];
            ArrayListIterator<char*> iter(l);
            int i=0;
            for(iter.first();!iter.isDone();iter.next(),i++){
                if(!strlen(*iter.current())){
                    char buf[256];
                    sprintf(buf,"V%d",i);
                    colNames[i] = strdup(buf);
                } else
                    colNames[i] = strdup(*iter.current());
                printf("Col %d: %s\n",i,colNames[i]);
            }
        } else {
            ArrayList<char *> *l = splitLine(s,delim,numCols);
            if(createList){
                ArrayList<Value> *out = Types::tList->set(linev);
                ArrayListIterator<char*> iter(l);
                int i=0;
                for(iter.first();!iter.isDone();iter.next(),i++){
                    char *s = *iter.current();
                    Value *vout = out->append();
                    if(types){
                        switch(types[i%numTypes]){
                        case 'i':
                            Types::tInteger->set(vout,atoi(s));
                            break;
                        case 'f':
                            Types::tFloat->set(vout,atof(s));
                            break;
                        case 's':
                        default:
                            Types::tString->set(vout,s);
                            break;
                        }
                    } else {
                        Types::tString->set(vout,s);
                    }
                }
            } else {
                Hash *out = Types::tHash->set(linev);
                ArrayListIterator<char*> iter(l);
                int i=0;
                for(iter.first();!iter.isDone();iter.next(),i++){
                    char *s = *iter.current();
                    Value vout;
                    if(types){
                        switch(types[i%numTypes]){
                        case 'i':
                            Types::tInteger->set(&vout,atoi(s));
                            break;
                        case 'f':
                            Types::tFloat->set(&vout,atof(s));
                            break;
                        case 's':
                        default:
                            Types::tString->set(&vout,s);
                            break;
                        }
                    } else {
                        Types::tString->set(&vout,s);
                    }
                    out->setSym(colNames[i],&vout);
                }

            }
        }
    }
};

static WrapperType<CSV> tCSV("CSVT");

%type csv tCSV CSV

%name csv
%shared

%wordargs make h (hash -- csv) start a new CSV object, given settings for reading
{
    CSV *c = new CSV(p0);
    tCSV.set(a->pushval(),c);
}

%wordargs line sA|csv (s csv -- val) parse a line, producing a hash or a list, or none if this was a skip or column header line.
{
    Value v;
    p1->line(&v,p0);
    a->pushval()->copy(&v);
}

%wordargs parseline si (s maxcols -- list) parse a single comma-separated line
{
    Value v;
    ArrayList<Value> *out = Types::tList->set(&v);
    ArrayList<char *> *list = splitLine(p0,',',p1);

    ArrayListIterator<char*> iter(list);
    for(iter.first();!iter.isDone();iter.next()){
        Value *vv = out->append();
        Types::tString->set(vv,*iter.current());
    }
    a->pushval()->copy(&v);
}

%init
{
    fprintf(stderr,"Initialising CSV plugin, %s %s\n",__DATE__,__TIME__);
}

<commit_msg>DON'T make the actual object GarbageCollected - just the wrapper!<commit_after>/**
 * @file csv.cpp
 * @brief CSV file handling.
 *
 * Usage:
 * csv$make takes a settings hash, and produces a CSV object.
 * csv$line handles a line in the CSV, typically read from a file,
 *     and returns a hash, list or none (if header or skip line
 *     was fed in).
 * csv$cols returns the columns list.
 *
 * Make hash parameters:
 *   `columns is a list of column names, which implies the csv has no header
 *   `list if true forces the output to be lists
 *   `nohead ignores the header even if no col names are given
 *           (names will be invented if the output is a hash)
 *   `skip defines a number of lines to ignore at the start
 *   `delimiter sets a delimiting character
 *   `types sets a column type string consisting of the chars "i",
 *          "f" or "s" (int,float,string). If only one char is
 *          provided, it's used for all cols. Otherwise the char
 *          used is types[colname%strlen(types)]
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>

#include <angort/angort.h>

#include "../hashgets.h"
#include "../wrappers.h"

using namespace angort;

// clear a string list and free all its strings
inline void clearList(ArrayList<char *> *l){
    ArrayListIterator<char*> iter(l);
    for(iter.first();!iter.isDone();iter.next()){
        free(*iter.current());
    }
    l->clear();
}

// temp list used for each line
static ArrayList<char*> list;

// add a new string to the list (takes a length because the list
// may not be null-terminated
void addToList(ArrayList<char *> *l,const char *s,int len){
    char **newfield = l->append();
    char *newstr = (char *)malloc(len+1);
    *newfield = newstr;
    memcpy(newstr,s,len);
    newstr[len]=0;
}

// split a null-terminated line, which must not end in \n.
// If at maxcols, delimiters are ignored.
static ArrayList<char*> *splitLine(const char *s,const char delim,int maxCols=0){
    // we add characters to this as we build up fields, it's
    // the easiest way to do quoting and escaping.
    char *fbuf=(char *)alloca(strlen(s));

    // static list of fields, reused for each line

    clearList(&list);
    // if non-zero, we are in a quoted field
    char quotechar = 0;
    int cols=0;
    char *fptr=fbuf; // field start ptr
    for(;;) {
        // two clauses here:
        // first says "if we're at the last column and the end,
        // fill in the last column." Second says "if columns are free,
        // or we're at or before the second to last column, and there's
        // and end or unquoted delimiter." If either are true, add.
        if(((cols==maxCols-1) && *s==0) || (
              (maxCols==0 || cols<(maxCols-1) ) &&
              (*s==0 || (*s==delim && !quotechar)))){
            // delimiter found, and not in quoted field, and not
            // at maxcolumns. Add string.
            addToList(&list,fbuf,fptr-fbuf);
            cols++;
            fptr=fbuf; // restart field buffer
        } else if(quotechar && *s==quotechar){
            // end of quote
            quotechar=0;
        } else if(*s=='\'' || *s == '\"'){
            // start of quote
            quotechar = *s;
        } else if(*s=='\\') {
            // escape char
            *fptr++ = *++s;
        } else {
            // ordinary char, add to buffer
            *fptr++ = *s;
        }

        if(*s==0)break;
        s++;
    }
    return &list;
}

class CSV  {
    int numCols;
    const char **colNames;
    bool noHead;
    int skipLines;
    bool createList;
    char delim;
    // if true, holds a string of column type chars. These are
    // s=str,f=float,i=int. If missing, all cols are strings.
    // If too short, is modded over i.e. so that a single "f" means all
    // cols are float.
    const char *types;
    int numTypes; // only valid if above is nonnull
    // the actual data, PER LINE. It's either a hash or a list.
    Value linev;

public:
    CSV(Hash *h){ // settings hash
        Value *v;
        colNames=NULL;
        if((v=h->getSym("columns"))!=NULL){
            // predefined column headers override those in the file
            ArrayList<Value> *l = Types::tList->get(v);
            numCols = l->count();
            colNames = new const char *[numCols];
            ArrayListIterator<Value> iter(l);
            int i=0;
            for(iter.first();!iter.isDone();iter.next()){
                colNames[i++] = strdup(iter.current()->toString().get());
            }

        }
        // do we consider the first line to be just data?
        noHead = hgetintdef(h,"nohead",0)!=0;

        // how many lines at the start do we skip?
        skipLines = hgetintdef(h,"skip",0);

        // do we create a hash for each line, or will a list do?
        createList = hgetintdef(h,"list",0)!=0;

        // delimiter
        delim = hgetstrdef(h,"delimiter",",")[0];

        // types
        types = hgetstrdef(h,"types",NULL);
        if(types && !*types)types=NULL; // don't allow empty str.
        if(types){
            types=strdup(types);
            numTypes = strlen(types);
        }
    }

    virtual ~CSV(){
        printf("Destuctor\n");
        if(colNames)
            delete colNames;
        if(types)
            free((void *)types);
    }

    // process a line of input and set the value accordingly
    void line(Value *linev,const char *s){
        // are we skipping?
        if(skipLines--){
            linev->clr();
        }

        if(!colNames && noHead){
            // no colnames and no head! We'll have to invent something.
            // we end up doing this twice, but it's only on the first line
            ArrayList<char *> *l = splitLine(s,delim,numCols);
            numCols = l->count();
            colNames = new const char *[numCols];
            for(int i=0;i<numCols;i++){
                char buf[256];
                sprintf(buf,"V%d",i);
                colNames[i]=strdup(buf);
            }
        }

        if(!colNames){ // no col names, but we are allowed a header
            //no, extract them
            ArrayList<char *> *l = splitLine(s,delim,0);
            numCols = l->count();
            colNames = new const char *[numCols];
            ArrayListIterator<char*> iter(l);
            int i=0;
            for(iter.first();!iter.isDone();iter.next(),i++){
                if(!strlen(*iter.current())){
                    char buf[256];
                    sprintf(buf,"V%d",i);
                    colNames[i] = strdup(buf);
                } else
                    colNames[i] = strdup(*iter.current());
                printf("Col %d: %s\n",i,colNames[i]);
            }
        } else {
            ArrayList<char *> *l = splitLine(s,delim,numCols);
            if(createList){
                ArrayList<Value> *out = Types::tList->set(linev);
                ArrayListIterator<char*> iter(l);
                int i=0;
                for(iter.first();!iter.isDone();iter.next(),i++){
                    char *s = *iter.current();
                    Value *vout = out->append();
                    if(types){
                        switch(types[i%numTypes]){
                        case 'i':
                            Types::tInteger->set(vout,atoi(s));
                            break;
                        case 'f':
                            Types::tFloat->set(vout,atof(s));
                            break;
                        case 's':
                        default:
                            Types::tString->set(vout,s);
                            break;
                        }
                    } else {
                        Types::tString->set(vout,s);
                    }
                }
            } else {
                Hash *out = Types::tHash->set(linev);
                ArrayListIterator<char*> iter(l);
                int i=0;
                for(iter.first();!iter.isDone();iter.next(),i++){
                    char *s = *iter.current();
                    Value vout;
                    if(types){
                        switch(types[i%numTypes]){
                        case 'i':
                            Types::tInteger->set(&vout,atoi(s));
                            break;
                        case 'f':
                            Types::tFloat->set(&vout,atof(s));
                            break;
                        case 's':
                        default:
                            Types::tString->set(&vout,s);
                            break;
                        }
                    } else {
                        Types::tString->set(&vout,s);
                    }
                    out->setSym(colNames[i],&vout);
                }

            }
        }
    }
};

static WrapperType<CSV> tCSV("CSVT");

%type csv tCSV CSV

%name csv
%shared

%wordargs make h (hash -- csv) start a new CSV object, given settings for reading
{
    CSV *c = new CSV(p0);
    tCSV.set(a->pushval(),c);
}

%wordargs line sA|csv (s csv -- val) parse a line, producing a hash or a list, or none if this was a skip or column header line.
{
    Value v;
    p1->line(&v,p0);
    a->pushval()->copy(&v);
}

%wordargs parseline si (s maxcols -- list) parse a single comma-separated line
{
    Value v;
    ArrayList<Value> *out = Types::tList->set(&v);
    ArrayList<char *> *list = splitLine(p0,',',p1);

    ArrayListIterator<char*> iter(list);
    for(iter.first();!iter.isDone();iter.next()){
        Value *vv = out->append();
        Types::tString->set(vv,*iter.current());
    }
    a->pushval()->copy(&v);
}

%init
{
    fprintf(stderr,"Initialising CSV plugin, %s %s\n",__DATE__,__TIME__);
}

<|endoftext|>


<commit_before>#include "hello.h"

int main()
{
  print_hello();
}
<commit_msg>Removed stale hello world file.<commit_after><|endoftext|>


<commit_before>/******************************************************************************
 Copyright 2015 Allied Telesis Labs Ltd. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice,
       this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.
*******************************************************************************/

#include <buildsys.h>

NameSpace::~NameSpace()
{
	while(!this->packages.empty()) {
		Package *p = this->packages.front();
		this->packages.pop_front();
		delete p;
	}
}

std::list < Package * >::iterator NameSpace::packagesStart()
{
	return this->packages.begin();
}

std::list < Package * >::iterator NameSpace::packagesEnd()
{
	return this->packages.end();
}

std::string NameSpace::getStagingDir()
{
	std::stringstream res;
	res << "output/" << this->getName() << "/staging";
	return res.str();
}

std::string NameSpace::getInstallDir()
{
	std::stringstream res;
	res << "output/" << this->getName() << "/install";
	return res.str();
}

Package *NameSpace::findPackage(std::string name)
{
	std::string file;
	std::string overlay;

	pthread_mutex_lock(&this->lock);
	std::list < Package * >::iterator iter = this->packagesStart();
	std::list < Package * >::iterator iterEnd = this->packagesEnd();
	for(; iter != iterEnd; iter++) {
		if((*iter)->getName().compare(name) == 0) {
			pthread_mutex_unlock(&this->lock);
			return (*iter);
		}
	}

	// Package not found, create it
	{
		// check that the dependency exists
		char *luaFile = NULL;
		char *dependPath = strdup(name.c_str());
		char *lastPart = strrchr(dependPath, '/');
		bool found = false;

		if(lastPart == NULL) {
			lastPart = strdup(dependPath);
		} else {
			lastPart = strdup(lastPart + 1);
		}

		string_list::iterator iter = this->WORLD->overlaysStart();
		string_list::iterator iterEnd = this->WORLD->overlaysEnd();
		for(; iter != iterEnd; iter++) {
			if(asprintf
			   (&luaFile, "%s/package/%s/%s.lua", iter->c_str(), dependPath,
			    lastPart) <= 0) {
				throw CustomException("Error with asprintf");
			}
			FILE *f = fopen(luaFile, "r");
			if(f != NULL) {
				found = true;
				overlay = *iter;
				fclose(f);
			}
			if(found) {
				break;
			}
			free(luaFile);
			luaFile = NULL;
		}

		if(!found) {
			throw CustomException("Failed opening Package");
		}

		free(dependPath);
		free(lastPart);

		file = std::string(luaFile);
		free(luaFile);
	}

	Package *p = new Package(this, name, file, overlay);
	this->_addPackage(p);

	pthread_mutex_unlock(&this->lock);

	return p;
}

void NameSpace::_addPackage(Package * p)
{
	this->packages.push_back(p);
	if(p->getNS() != this)
		p->setNS(this);
};

void NameSpace::addPackage(Package * p)
{
	pthread_mutex_lock(&this->lock);
	this->_addPackage(p);
	pthread_mutex_unlock(&this->lock);
}

void NameSpace::_removePackage(Package * p)
{
	this->packages.remove(p);
}

void NameSpace::removePackage(Package * p)
{
	pthread_mutex_lock(&this->lock);
	this->_removePackage(p);
	pthread_mutex_unlock(&this->lock);
}

World *NameSpace::getWorld()
{
	return this->WORLD;
}
<commit_msg>namespace: add package name to error message<commit_after>/******************************************************************************
 Copyright 2015 Allied Telesis Labs Ltd. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice,
       this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.
*******************************************************************************/

#include <buildsys.h>

NameSpace::~NameSpace()
{
	while(!this->packages.empty()) {
		Package *p = this->packages.front();
		this->packages.pop_front();
		delete p;
	}
}

std::list < Package * >::iterator NameSpace::packagesStart()
{
	return this->packages.begin();
}

std::list < Package * >::iterator NameSpace::packagesEnd()
{
	return this->packages.end();
}

std::string NameSpace::getStagingDir()
{
	std::stringstream res;
	res << "output/" << this->getName() << "/staging";
	return res.str();
}

std::string NameSpace::getInstallDir()
{
	std::stringstream res;
	res << "output/" << this->getName() << "/install";
	return res.str();
}

Package *NameSpace::findPackage(std::string name)
{
	std::string file;
	std::string overlay;

	pthread_mutex_lock(&this->lock);
	std::list < Package * >::iterator iter = this->packagesStart();
	std::list < Package * >::iterator iterEnd = this->packagesEnd();
	for(; iter != iterEnd; iter++) {
		if((*iter)->getName().compare(name) == 0) {
			pthread_mutex_unlock(&this->lock);
			return (*iter);
		}
	}

	// Package not found, create it
	{
		// check that the dependency exists
		char *luaFile = NULL;
		char *dependPath = strdup(name.c_str());
		char *lastPart = strrchr(dependPath, '/');
		bool found = false;

		if(lastPart == NULL) {
			lastPart = strdup(dependPath);
		} else {
			lastPart = strdup(lastPart + 1);
		}

		string_list::iterator iter = this->WORLD->overlaysStart();
		string_list::iterator iterEnd = this->WORLD->overlaysEnd();
		for(; iter != iterEnd; iter++) {
			if(asprintf
			   (&luaFile, "%s/package/%s/%s.lua", iter->c_str(), dependPath,
			    lastPart) <= 0) {
				throw CustomException("Error with asprintf");
			}
			FILE *f = fopen(luaFile, "r");
			if(f != NULL) {
				found = true;
				overlay = *iter;
				fclose(f);
			}
			if(found) {
				break;
			}
			free(luaFile);
			luaFile = NULL;
		}

		if(!found) {
			throw CustomException("Package not found: " + name);
		}

		free(dependPath);
		free(lastPart);

		file = std::string(luaFile);
		free(luaFile);
	}

	Package *p = new Package(this, name, file, overlay);
	this->_addPackage(p);

	pthread_mutex_unlock(&this->lock);

	return p;
}

void NameSpace::_addPackage(Package * p)
{
	this->packages.push_back(p);
	if(p->getNS() != this)
		p->setNS(this);
};

void NameSpace::addPackage(Package * p)
{
	pthread_mutex_lock(&this->lock);
	this->_addPackage(p);
	pthread_mutex_unlock(&this->lock);
}

void NameSpace::_removePackage(Package * p)
{
	this->packages.remove(p);
}

void NameSpace::removePackage(Package * p)
{
	pthread_mutex_lock(&this->lock);
	this->_removePackage(p);
	pthread_mutex_unlock(&this->lock);
}

World *NameSpace::getWorld()
{
	return this->WORLD;
}
<|endoftext|>


<commit_before>#include <windows.h>

int APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
	switch (Reason)
	{
	case DLL_PROCESS_ATTACH:
		{
			char ini_path[MAX_PATH] = { 0 };
			char * temp_path;
			/* get our current path so that we can load stuff from our settings */
			GetModuleFileNameA(hDLL, ini_path, MAX_PATH);
			temp_path = strrchr(ini_path, '\\');
			temp_path[1] = '\0';
			strcat_s(ini_path, MAX_PATH, "\\bootstrap.ini");
			char bootstrap_dll[MAX_PATH] = { 0 };
			GetPrivateProfileStringA("bootstrap", "dll", NULL, bootstrap_dll, MAX_PATH, ini_path);
			/* at this point we should be in process. we should load our bootstrapped dll here and unload ourselves */
			if (bootstrap_dll != NULL && bootstrap_dll[0] != NULL)
				LoadLibraryA(bootstrap_dll);
		}
		break;
	case DLL_PROCESS_DETACH:
		break;
	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:
		break;
	}

	return TRUE;
}
<commit_msg>included `stat` function, we now check to make sure the file exists before trying to load it<commit_after>#include <windows.h>
#include <sys/stat.h>

int APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
	switch (Reason)
	{
	case DLL_PROCESS_ATTACH:
		{
			char ini_path[MAX_PATH] = { 0 };
			char * temp_path;
			struct stat buffer;
			/* get our current path so that we can load stuff from our settings */
			GetModuleFileNameA(hDLL, ini_path, MAX_PATH);
			temp_path = strrchr(ini_path, '\\');
			temp_path[1] = '\0';
			strcat_s(ini_path, MAX_PATH, "\\bootstrap.ini");
			char bootstrap_dll[MAX_PATH] = { 0 };
			GetPrivateProfileStringA("bootstrap", "dll", NULL, bootstrap_dll, MAX_PATH, ini_path);
			/* at this point we should be in process. we should load our bootstrapped dll here and unload ourselves */
			if (bootstrap_dll != NULL && bootstrap_dll[0] != NULL)
				if (stat(bootstrap_dll, &buffer) == 0)
					LoadLibraryA(bootstrap_dll);
		}
		break;
	case DLL_PROCESS_DETACH:
		break;
	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:
		break;
	}

	return TRUE;
}
<|endoftext|>