<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "profile.h"

#include "settings.h"

#include <logging/translator.h>
#include <tools/error.h>

namespace qbs {

/*!
 * \class Profile
 * \brief The \c Profile class gives access to the settings of a given profile.
 */

 /*!
 * \enum Profile::KeySelection
 * This enum type specifies whether to enumerate keys recursively.
 * \value KeySelectionRecursive Indicates that key enumeration should happen recursively, i.e.
 *        it should go up the base profile chain.
 * \value KeySelectionNonRecursive Indicates that only keys directly attached to a profile
 *        should be listed.
 */

/*!
 * \brief Creates an object giving access to the settings for profile \c name.
 */
Profile::Profile(const QString &name, Settings *settings) : m_name(name), m_settings(settings)
{
}

/*!
 * \brief Returns the value for property \c key in this profile.
 */
QVariant Profile::value(const QString &key, const QVariant &defaultValue) const
{
    return possiblyInheritedValue(key, defaultValue, QStringList());
}

/*!
 * \brief Gives value \c value to the property \c key in this profile.
 */
void Profile::setValue(const QString &key, const QVariant &value)
{
    m_settings->setValue(fullyQualifiedKey(key), value);
}

/*!
 * \brief Removes a key and the associated value from this profile.
 */
void Profile::remove(const QString &key)
{
    m_settings->remove(fullyQualifiedKey(key));
}

/*!
 * \brief Returns the name of this profile.
 */
QString Profile::name() const
{
    return m_name;
}

/*!
 * \brief Returns all property keys in this profile.
 * If and only if selection is Profile::KeySelectionRecursive, this will also list keys defined
 * in base profiles.
 */
QStringList Profile::allKeys(KeySelection selection) const
{
    return allKeysInternal(selection, QStringList());
}

/*!
 * \brief Returns the name of this profile's base profile.
 * The returned value is empty if the profile does not have a base profile.
 */
QString Profile::baseProfile() const
{
    return localValue(baseProfileKey()).toString();
}

/*!
 * \brief Sets a new base profile for this profile.
 */
void Profile::setBaseProfile(const QString &baseProfile)
{
    setValue(baseProfileKey(), baseProfile);
}

/*!
 * \brief Removes this profile's base profile setting.
 */
void Profile::removeBaseProfile()
{
    remove(baseProfileKey());
}

/*!
 * \brief Removes this profile from the settings.
 */
void Profile::removeProfile()
{
    remove(profileKey());
}

QString Profile::profileKey() const
{
    return QLatin1String("profiles.") + m_name;
}

QString Profile::baseProfileKey()
{
    return QLatin1String("baseProfile");
}

QVariant Profile::localValue(const QString &key) const
{
    return m_settings->value(fullyQualifiedKey(key));
}

QString Profile::fullyQualifiedKey(const QString &key) const
{
    return profileKey() + QLatin1Char('.') + key;
}

QVariant Profile::possiblyInheritedValue(const QString &key, const QVariant &defaultValue,
                                         QStringList profileChain) const
{
    extendAndCheckProfileChain(profileChain);
    const QVariant v = localValue(key);
    if (v.isValid())
        return v;
    const QString baseProfileName = baseProfile();
    if (baseProfileName.isEmpty())
        return defaultValue;
    Profile parentProfile(baseProfileName, m_settings);
    return parentProfile.possiblyInheritedValue(key, defaultValue, profileChain);
}

QStringList Profile::allKeysInternal(Profile::KeySelection selection,
                                     QStringList profileChain) const
{
    extendAndCheckProfileChain(profileChain);
    QStringList keys = m_settings->allKeysWithPrefix(profileKey());
    if (selection == KeySelectionNonRecursive)
        return keys;
    const QString baseProfileName = baseProfile();
    if (baseProfileName.isEmpty())
        return keys;
    Profile parentProfile(baseProfileName, m_settings);
    keys += parentProfile.allKeysInternal(KeySelectionRecursive, profileChain);
    keys.removeDuplicates();
    keys.removeOne(baseProfileKey());
    keys.sort();
    return keys;
}

void Profile::extendAndCheckProfileChain(QStringList &chain) const
{
    chain << m_name;
    if (chain.count(m_name) > 1) {
        throw Error(Internal::Tr::tr("Circular profile inheritance. Cycle is '%1'.")
                    .arg(chain.join(QLatin1String(" -> "))));
    }
}

} // namespace qbs
<commit_msg>fix Profile::removeProfile<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "profile.h"

#include "settings.h"

#include <logging/translator.h>
#include <tools/error.h>

namespace qbs {

/*!
 * \class Profile
 * \brief The \c Profile class gives access to the settings of a given profile.
 */

 /*!
 * \enum Profile::KeySelection
 * This enum type specifies whether to enumerate keys recursively.
 * \value KeySelectionRecursive Indicates that key enumeration should happen recursively, i.e.
 *        it should go up the base profile chain.
 * \value KeySelectionNonRecursive Indicates that only keys directly attached to a profile
 *        should be listed.
 */

/*!
 * \brief Creates an object giving access to the settings for profile \c name.
 */
Profile::Profile(const QString &name, Settings *settings) : m_name(name), m_settings(settings)
{
}

/*!
 * \brief Returns the value for property \c key in this profile.
 */
QVariant Profile::value(const QString &key, const QVariant &defaultValue) const
{
    return possiblyInheritedValue(key, defaultValue, QStringList());
}

/*!
 * \brief Gives value \c value to the property \c key in this profile.
 */
void Profile::setValue(const QString &key, const QVariant &value)
{
    m_settings->setValue(fullyQualifiedKey(key), value);
}

/*!
 * \brief Removes a key and the associated value from this profile.
 */
void Profile::remove(const QString &key)
{
    m_settings->remove(fullyQualifiedKey(key));
}

/*!
 * \brief Returns the name of this profile.
 */
QString Profile::name() const
{
    return m_name;
}

/*!
 * \brief Returns all property keys in this profile.
 * If and only if selection is Profile::KeySelectionRecursive, this will also list keys defined
 * in base profiles.
 */
QStringList Profile::allKeys(KeySelection selection) const
{
    return allKeysInternal(selection, QStringList());
}

/*!
 * \brief Returns the name of this profile's base profile.
 * The returned value is empty if the profile does not have a base profile.
 */
QString Profile::baseProfile() const
{
    return localValue(baseProfileKey()).toString();
}

/*!
 * \brief Sets a new base profile for this profile.
 */
void Profile::setBaseProfile(const QString &baseProfile)
{
    setValue(baseProfileKey(), baseProfile);
}

/*!
 * \brief Removes this profile's base profile setting.
 */
void Profile::removeBaseProfile()
{
    remove(baseProfileKey());
}

/*!
 * \brief Removes this profile from the settings.
 */
void Profile::removeProfile()
{
    m_settings->remove(profileKey());
}

QString Profile::profileKey() const
{
    return QLatin1String("profiles.") + m_name;
}

QString Profile::baseProfileKey()
{
    return QLatin1String("baseProfile");
}

QVariant Profile::localValue(const QString &key) const
{
    return m_settings->value(fullyQualifiedKey(key));
}

QString Profile::fullyQualifiedKey(const QString &key) const
{
    return profileKey() + QLatin1Char('.') + key;
}

QVariant Profile::possiblyInheritedValue(const QString &key, const QVariant &defaultValue,
                                         QStringList profileChain) const
{
    extendAndCheckProfileChain(profileChain);
    const QVariant v = localValue(key);
    if (v.isValid())
        return v;
    const QString baseProfileName = baseProfile();
    if (baseProfileName.isEmpty())
        return defaultValue;
    Profile parentProfile(baseProfileName, m_settings);
    return parentProfile.possiblyInheritedValue(key, defaultValue, profileChain);
}

QStringList Profile::allKeysInternal(Profile::KeySelection selection,
                                     QStringList profileChain) const
{
    extendAndCheckProfileChain(profileChain);
    QStringList keys = m_settings->allKeysWithPrefix(profileKey());
    if (selection == KeySelectionNonRecursive)
        return keys;
    const QString baseProfileName = baseProfile();
    if (baseProfileName.isEmpty())
        return keys;
    Profile parentProfile(baseProfileName, m_settings);
    keys += parentProfile.allKeysInternal(KeySelectionRecursive, profileChain);
    keys.removeDuplicates();
    keys.removeOne(baseProfileKey());
    keys.sort();
    return keys;
}

void Profile::extendAndCheckProfileChain(QStringList &chain) const
{
    chain << m_name;
    if (chain.count(m_name) > 1) {
        throw Error(Internal::Tr::tr("Circular profile inheritance. Cycle is '%1'.")
                    .arg(chain.join(QLatin1String(" -> "))));
    }
}

} // namespace qbs
<|endoftext|>


<commit_before>#ifndef _WIN32

//===--- TerminalDisplayUnix.cpp - Output To UNIX Terminal ------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the interface for writing to a UNIX terminal. It tries to
//  support all "common" terminal types.
//
//  Axel Naumann <axel@cern.ch>, 2011-05-12
//===----------------------------------------------------------------------===//

#include "textinput/TerminalDisplayUnix.h"

#include <fcntl.h>
#include <stdio.h>
// putenv not in cstdlib on Solaris
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <csignal>
#include <cstring>
#include <sstream>
#include <string>

#include "textinput/Color.h"
#include "textinput/Display.h"
#include "textinput/TerminalConfigUnix.h"

using std::signal;
using std::strstr;

namespace {
  textinput::TerminalDisplayUnix*& gTerminalDisplayUnix() {
    static textinput::TerminalDisplayUnix* S = 0;
    return S;
  }

  void InitRGB256(unsigned char rgb256[][3]) {
    // initialize the array with the expected standard colors:
    // (from http://frexx.de/xterm-256-notes)

    // this is not what I see, though it's supposedly the default:
    //   rgb[0][0] =   0; rgb[0][1] =   0; rgb[0][1] =   0;
    // use this instead, just to be on the safe side:
    rgb256[0][0] =  46; rgb256[0][1] =  52; rgb256[0][2] =  64;
    rgb256[1][0] = 205; rgb256[1][1] =   0; rgb256[1][2] =   0;
    rgb256[2][0] =   0; rgb256[2][1] = 205; rgb256[2][2] =   0;
    rgb256[3][0] = 205; rgb256[3][1] = 205; rgb256[3][2] =   0;
    rgb256[4][0] =   0; rgb256[4][1] =   0; rgb256[4][2] = 238;
    rgb256[5][0] = 205; rgb256[5][1] =   0; rgb256[5][2] = 205;
    rgb256[6][0] =   0; rgb256[6][1] = 205; rgb256[6][2] = 205;
    rgb256[7][0] = 229; rgb256[7][1] = 229; rgb256[7][2] = 229;

    // this is not what I see, though it's supposedly the default:
    //   rgb256[ 8][0] = 127; rgb256[ 8][1] = 127; rgb256[ 8][1] = 127;
    // use this instead, just to be on the safe side:
    rgb256[ 8][0] =   0; rgb256[ 8][1] =   0; rgb256[ 8][2] =   0;
    rgb256[ 9][0] = 255; rgb256[ 9][1] =   0; rgb256[ 9][2] =   0;
    rgb256[10][0] =   0; rgb256[10][1] = 255; rgb256[10][2] =   0;
    rgb256[11][0] = 255; rgb256[11][1] = 255; rgb256[11][2] =   0;
    rgb256[12][0] =  92; rgb256[12][1] =  92; rgb256[12][2] = 255;
    rgb256[13][0] = 255; rgb256[13][1] =   0; rgb256[13][2] = 255;
    rgb256[14][0] =   0; rgb256[14][1] = 255; rgb256[14][2] = 255;
    rgb256[15][0] = 255; rgb256[15][1] = 255; rgb256[15][2] = 255;

    // 6 intensity RGB
    static const int intensities[] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff};
    int idx = 16;
    for (int r = 0; r < 6; ++r) {
      for (int g = 0; g < 6; ++g) {
        for (int b = 0; b < 6; ++b) {
          rgb256[idx][0] = intensities[r];
          rgb256[idx][1] = intensities[g];
          rgb256[idx][2] = intensities[b];
          ++idx;
        }
      }
    }

    // colors 232-255 are a grayscale ramp, intentionally leaving out
    // black and white
    for (unsigned char gray = 0; gray < 24; ++gray) {
      unsigned char level = (gray * 10) + 8;
      rgb256[232 + gray][0] = level;
      rgb256[232 + gray][1] = level;
      rgb256[232 + gray][2] = level;
    }
  }
} // unnamed namespace

extern "C" void TerminalDisplayUnix__handleResizeSignal(int) {
  gTerminalDisplayUnix()->HandleResizeSignal();
}

namespace textinput {
  // If input is not a tty don't write in tty-mode either.
  TerminalDisplayUnix::TerminalDisplayUnix():
    TerminalDisplay(TerminalConfigUnix::Get().IsInteractive()),
    fIsAttached(false), fNColors(16), fOutputID(STDOUT_FILENO)
  {
    if (::isatty(::fileno(stdin)) && !::isatty(fOutputID)) {
      // Display prompt, even if stdout is going somewhere else
      fOutputID = ::open("/dev/tty", O_WRONLY);
      SetIsTTY(true);
    }

    HandleResizeSignal(); // needs fOutputID
    gTerminalDisplayUnix() = this;
    signal(SIGWINCH, TerminalDisplayUnix__handleResizeSignal);
#ifdef TCSANOW
    TerminalConfigUnix::Get().TIOS()->c_lflag &= ~(ECHO);
    TerminalConfigUnix::Get().TIOS()->c_lflag |= ECHOCTL|ECHOKE|ECHOE;
#endif
    const char* TERM = getenv("TERM");
    if (TERM &&  strstr(TERM, "256")) {
      fNColors = 256;
    }
  }

  static void syncOut(int fd) {
    ::fflush(stdout);
  }

  TerminalDisplayUnix::~TerminalDisplayUnix() {
    Detach();
    if (fOutputID != STDOUT_FILENO) {
      syncOut(fOutputID);
      ::close(fOutputID);
    }
  }

  void
  TerminalDisplayUnix::HandleResizeSignal() {
#ifdef TIOCGWINSZ
    struct winsize sz;
    int ret = ioctl(fOutputID, TIOCGWINSZ, (char*)&sz);
    if (!ret && sz.ws_col) {
      SetWidth(sz.ws_col);

      // Export what we found.
      std::stringstream s;
      s << sz.ws_col;
      setenv("COLUMS", s.str().c_str(), 1 /*overwrite*/);
      s.clear();
      s << sz.ws_row;
      setenv("LINES", s.str().c_str(), 1 /*overwrite*/);
    }
#else
    // try $COLUMNS
    const char* COLUMNS = getenv("COLUMNS");
    if (COLUMNS) {
      long width = atol(COLUMNS);
      if (width > 4 && width < 1024*16) {
        SetWidth(width);
      }
    }
#endif
  }

  void
  TerminalDisplayUnix::SetColor(char CIdx, const Color& C) {
    if (!IsTTY()) return;

    // Default color, reset previous bold etc.
    static const char text[] = {(char)0x1b, '[', '0', 'm'};
    WriteRawString(text, sizeof(text));

    if (CIdx == 0) return;

    if (fNColors == 256) {
      int ANSIIdx = GetClosestColorIdx256(C);
      static const char preamble[] = {'\x1b', '[', '3', '8', ';', '5', ';', 0};
      std::string buf(preamble);
      if (ANSIIdx > 100) {
        buf += '0' + (ANSIIdx / 100);
      }
      if (ANSIIdx > 10) {
        buf += '0' + ((ANSIIdx / 10) % 10);
      }
      buf += '0' + (ANSIIdx % 10);
      buf +=  "m";
      WriteRawString(buf.c_str(), buf.length());
    } else {
      int ANSIIdx = GetClosestColorIdx16(C);
      char buf[] = {'\x1b', '[', '3', static_cast<char>('0' + (ANSIIdx % 8)), 'm', 0};
      if (ANSIIdx > 7) buf[2] += 6;
      WriteRawString(buf, 5);
    }

    if (C.fModifiers & Color::kModUnderline) {
      WriteRawString("\033[4m", 4);
    }
    if (C.fModifiers & Color::kModBold) {
      WriteRawString("\033[1m", 4);
    }
    if (C.fModifiers & Color::kModInverse) {
      WriteRawString("\033[7m", 4);
    }

  }

  void
  TerminalDisplayUnix::MoveFront() {
    static const char text[] = {(char)0x1b, '[', '1', 'G'};
    if (!IsTTY()) return;
    WriteRawString(text, sizeof(text));
  }

  void
  TerminalDisplayUnix::MoveInternal(char What, size_t n) {
    static const char cmd[] = "\x1b[";
    if (!IsTTY()) return;
    std::string text;
    for (size_t i = 0; i < n; ++i) {
      text += cmd;
      text += What;
    }
    WriteRawString(text.c_str(), text.length());
  }

  void
  TerminalDisplayUnix::MoveUp(size_t nLines /* = 1 */) {
    MoveInternal('A', nLines);
  }

  void
  TerminalDisplayUnix::MoveDown(size_t nLines /* = 1 */) {
    MoveInternal('B', nLines);
  }

  void
  TerminalDisplayUnix::MoveRight(size_t nCols /* = 1 */) {
    MoveInternal('C', nCols);
  }

  void
  TerminalDisplayUnix::MoveLeft(size_t nCols /* = 1 */) {
    MoveInternal('D', nCols);
  }

  ////////////////////////////////////////////////////////////////////////////////
  /// Erases the input to the right of the cursor.
  void
  TerminalDisplayUnix::EraseToRight() {
    static const char text[] = {(char)0x1b, '[', 'K'}; // ESC[K
    if (!IsTTY()) return;
    WriteRawString(text, sizeof(text));
  }

  ////////////////////////////////////////////////////////////////////////////////
  /// Writes out a raw string to stdout.
  ///
  /// \param[in] text raw string to be written out
  /// \param[in] len length of the raw string
  void
  TerminalDisplayUnix::WriteRawString(const char *text, size_t len) {
    if (write(fOutputID, text, len) == -1) {
      // Silence Ubuntu's "unused result". We don't care if it fails.
    }
  }

  ////////////////////////////////////////////////////////////////////////////////
  /// Invoke this on EOL. Writes out space backspace, to wrap to the next line.
  /// Otherwise, we stay on the same line and the input gets pushed upwards.
  void
  TerminalDisplayUnix::ActOnEOL() {
    if (!IsTTY()) return;
    WriteRawString(" \b", 2);
    //MoveUp();
  }

  void
  TerminalDisplayUnix::Attach() {
    // set to noecho
    if (fIsAttached) return;
    syncOut(fOutputID);
    TerminalConfigUnix::Get().Attach();
    fWritePos = Pos();
    fWriteLen = 0;
    fIsAttached = true;
  }

  void
  TerminalDisplayUnix::Detach() {
    if (!fIsAttached) return;
    syncOut(fOutputID);
    TerminalConfigUnix::Get().Detach();
    TerminalDisplay::Detach();
    fIsAttached = false;
  }

  int
  TerminalDisplayUnix::GetClosestColorIdx16(const Color& C) {
    int r = C.fR;
    int g = C.fG;
    int b = C.fB;
    int sum = r + g + b;
    r = r > sum / 4;
    g = g > sum / 4;
    b = b > sum / 4;

    // ANSI:
    return r + (g * 2) + (b * 4);
    // ! ANSI:
    // return (r * 4) + (g * 2) + b;
  }

  int
  TerminalDisplayUnix::GetClosestColorIdx256(const Color& C) {
    static unsigned char rgb256[256][3] = {{0}};
    if (rgb256[0][0] == 0) {
      InitRGB256(rgb256);
    }

    // Find the closest index.
    // A: the closest color match (square of geometric distance in RGB)
    // B: the closest brightness match
    // Treat them equally, which suppresses differences
    // in color due to squared distance.

    // start with black:
    int idx = 0;
    unsigned int r = C.fR;
    unsigned int g = C.fG;
    unsigned int b = C.fB;
    unsigned int graylvl = (r + g + b)/3;
    long mindelta = (r*r + g*g + b*b) + graylvl;
    if (mindelta) {
      for (unsigned int i = 0; i < 256; ++i) {
        long delta = (rgb256[i][0] + rgb256[i][1] + rgb256[i][2])/3 - graylvl;
        if (delta < 0) delta = -delta;
        delta += (r-rgb256[i][0])*(r-rgb256[i][0]) +
        (g-rgb256[i][1])*(g-rgb256[i][1]) +
        (b-rgb256[i][2])*(b-rgb256[i][2]);

        if (delta < mindelta) {
          mindelta = delta;
          idx = i;
          if (mindelta == 0) break;
        }
      }
    }
    return idx;
  }

}

#endif // #ifndef _WIN32
<commit_msg>Silence unused param warning, if this is what this should do?<commit_after>#ifndef _WIN32

//===--- TerminalDisplayUnix.cpp - Output To UNIX Terminal ------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the interface for writing to a UNIX terminal. It tries to
//  support all "common" terminal types.
//
//  Axel Naumann <axel@cern.ch>, 2011-05-12
//===----------------------------------------------------------------------===//

#include "textinput/TerminalDisplayUnix.h"

#include <fcntl.h>
#include <stdio.h>
// putenv not in cstdlib on Solaris
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <csignal>
#include <cstring>
#include <sstream>
#include <string>

#include "textinput/Color.h"
#include "textinput/Display.h"
#include "textinput/TerminalConfigUnix.h"

using std::signal;
using std::strstr;

namespace {
  textinput::TerminalDisplayUnix*& gTerminalDisplayUnix() {
    static textinput::TerminalDisplayUnix* S = 0;
    return S;
  }

  void InitRGB256(unsigned char rgb256[][3]) {
    // initialize the array with the expected standard colors:
    // (from http://frexx.de/xterm-256-notes)

    // this is not what I see, though it's supposedly the default:
    //   rgb[0][0] =   0; rgb[0][1] =   0; rgb[0][1] =   0;
    // use this instead, just to be on the safe side:
    rgb256[0][0] =  46; rgb256[0][1] =  52; rgb256[0][2] =  64;
    rgb256[1][0] = 205; rgb256[1][1] =   0; rgb256[1][2] =   0;
    rgb256[2][0] =   0; rgb256[2][1] = 205; rgb256[2][2] =   0;
    rgb256[3][0] = 205; rgb256[3][1] = 205; rgb256[3][2] =   0;
    rgb256[4][0] =   0; rgb256[4][1] =   0; rgb256[4][2] = 238;
    rgb256[5][0] = 205; rgb256[5][1] =   0; rgb256[5][2] = 205;
    rgb256[6][0] =   0; rgb256[6][1] = 205; rgb256[6][2] = 205;
    rgb256[7][0] = 229; rgb256[7][1] = 229; rgb256[7][2] = 229;

    // this is not what I see, though it's supposedly the default:
    //   rgb256[ 8][0] = 127; rgb256[ 8][1] = 127; rgb256[ 8][1] = 127;
    // use this instead, just to be on the safe side:
    rgb256[ 8][0] =   0; rgb256[ 8][1] =   0; rgb256[ 8][2] =   0;
    rgb256[ 9][0] = 255; rgb256[ 9][1] =   0; rgb256[ 9][2] =   0;
    rgb256[10][0] =   0; rgb256[10][1] = 255; rgb256[10][2] =   0;
    rgb256[11][0] = 255; rgb256[11][1] = 255; rgb256[11][2] =   0;
    rgb256[12][0] =  92; rgb256[12][1] =  92; rgb256[12][2] = 255;
    rgb256[13][0] = 255; rgb256[13][1] =   0; rgb256[13][2] = 255;
    rgb256[14][0] =   0; rgb256[14][1] = 255; rgb256[14][2] = 255;
    rgb256[15][0] = 255; rgb256[15][1] = 255; rgb256[15][2] = 255;

    // 6 intensity RGB
    static const int intensities[] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff};
    int idx = 16;
    for (int r = 0; r < 6; ++r) {
      for (int g = 0; g < 6; ++g) {
        for (int b = 0; b < 6; ++b) {
          rgb256[idx][0] = intensities[r];
          rgb256[idx][1] = intensities[g];
          rgb256[idx][2] = intensities[b];
          ++idx;
        }
      }
    }

    // colors 232-255 are a grayscale ramp, intentionally leaving out
    // black and white
    for (unsigned char gray = 0; gray < 24; ++gray) {
      unsigned char level = (gray * 10) + 8;
      rgb256[232 + gray][0] = level;
      rgb256[232 + gray][1] = level;
      rgb256[232 + gray][2] = level;
    }
  }
} // unnamed namespace

extern "C" void TerminalDisplayUnix__handleResizeSignal(int) {
  gTerminalDisplayUnix()->HandleResizeSignal();
}

namespace textinput {
  // If input is not a tty don't write in tty-mode either.
  TerminalDisplayUnix::TerminalDisplayUnix():
    TerminalDisplay(TerminalConfigUnix::Get().IsInteractive()),
    fIsAttached(false), fNColors(16), fOutputID(STDOUT_FILENO)
  {
    if (::isatty(::fileno(stdin)) && !::isatty(fOutputID)) {
      // Display prompt, even if stdout is going somewhere else
      fOutputID = ::open("/dev/tty", O_WRONLY);
      SetIsTTY(true);
    }

    HandleResizeSignal(); // needs fOutputID
    gTerminalDisplayUnix() = this;
    signal(SIGWINCH, TerminalDisplayUnix__handleResizeSignal);
#ifdef TCSANOW
    TerminalConfigUnix::Get().TIOS()->c_lflag &= ~(ECHO);
    TerminalConfigUnix::Get().TIOS()->c_lflag |= ECHOCTL|ECHOKE|ECHOE;
#endif
    const char* TERM = getenv("TERM");
    if (TERM &&  strstr(TERM, "256")) {
      fNColors = 256;
    }
  }

  static void syncOut(int /*fd*/) {
    ::fflush(stdout);
  }

  TerminalDisplayUnix::~TerminalDisplayUnix() {
    Detach();
    if (fOutputID != STDOUT_FILENO) {
      syncOut(fOutputID);
      ::close(fOutputID);
    }
  }

  void
  TerminalDisplayUnix::HandleResizeSignal() {
#ifdef TIOCGWINSZ
    struct winsize sz;
    int ret = ioctl(fOutputID, TIOCGWINSZ, (char*)&sz);
    if (!ret && sz.ws_col) {
      SetWidth(sz.ws_col);

      // Export what we found.
      std::stringstream s;
      s << sz.ws_col;
      setenv("COLUMS", s.str().c_str(), 1 /*overwrite*/);
      s.clear();
      s << sz.ws_row;
      setenv("LINES", s.str().c_str(), 1 /*overwrite*/);
    }
#else
    // try $COLUMNS
    const char* COLUMNS = getenv("COLUMNS");
    if (COLUMNS) {
      long width = atol(COLUMNS);
      if (width > 4 && width < 1024*16) {
        SetWidth(width);
      }
    }
#endif
  }

  void
  TerminalDisplayUnix::SetColor(char CIdx, const Color& C) {
    if (!IsTTY()) return;

    // Default color, reset previous bold etc.
    static const char text[] = {(char)0x1b, '[', '0', 'm'};
    WriteRawString(text, sizeof(text));

    if (CIdx == 0) return;

    if (fNColors == 256) {
      int ANSIIdx = GetClosestColorIdx256(C);
      static const char preamble[] = {'\x1b', '[', '3', '8', ';', '5', ';', 0};
      std::string buf(preamble);
      if (ANSIIdx > 100) {
        buf += '0' + (ANSIIdx / 100);
      }
      if (ANSIIdx > 10) {
        buf += '0' + ((ANSIIdx / 10) % 10);
      }
      buf += '0' + (ANSIIdx % 10);
      buf +=  "m";
      WriteRawString(buf.c_str(), buf.length());
    } else {
      int ANSIIdx = GetClosestColorIdx16(C);
      char buf[] = {'\x1b', '[', '3', static_cast<char>('0' + (ANSIIdx % 8)), 'm', 0};
      if (ANSIIdx > 7) buf[2] += 6;
      WriteRawString(buf, 5);
    }

    if (C.fModifiers & Color::kModUnderline) {
      WriteRawString("\033[4m", 4);
    }
    if (C.fModifiers & Color::kModBold) {
      WriteRawString("\033[1m", 4);
    }
    if (C.fModifiers & Color::kModInverse) {
      WriteRawString("\033[7m", 4);
    }

  }

  void
  TerminalDisplayUnix::MoveFront() {
    static const char text[] = {(char)0x1b, '[', '1', 'G'};
    if (!IsTTY()) return;
    WriteRawString(text, sizeof(text));
  }

  void
  TerminalDisplayUnix::MoveInternal(char What, size_t n) {
    static const char cmd[] = "\x1b[";
    if (!IsTTY()) return;
    std::string text;
    for (size_t i = 0; i < n; ++i) {
      text += cmd;
      text += What;
    }
    WriteRawString(text.c_str(), text.length());
  }

  void
  TerminalDisplayUnix::MoveUp(size_t nLines /* = 1 */) {
    MoveInternal('A', nLines);
  }

  void
  TerminalDisplayUnix::MoveDown(size_t nLines /* = 1 */) {
    MoveInternal('B', nLines);
  }

  void
  TerminalDisplayUnix::MoveRight(size_t nCols /* = 1 */) {
    MoveInternal('C', nCols);
  }

  void
  TerminalDisplayUnix::MoveLeft(size_t nCols /* = 1 */) {
    MoveInternal('D', nCols);
  }

  ////////////////////////////////////////////////////////////////////////////////
  /// Erases the input to the right of the cursor.
  void
  TerminalDisplayUnix::EraseToRight() {
    static const char text[] = {(char)0x1b, '[', 'K'}; // ESC[K
    if (!IsTTY()) return;
    WriteRawString(text, sizeof(text));
  }

  ////////////////////////////////////////////////////////////////////////////////
  /// Writes out a raw string to stdout.
  ///
  /// \param[in] text raw string to be written out
  /// \param[in] len length of the raw string
  void
  TerminalDisplayUnix::WriteRawString(const char *text, size_t len) {
    if (write(fOutputID, text, len) == -1) {
      // Silence Ubuntu's "unused result". We don't care if it fails.
    }
  }

  ////////////////////////////////////////////////////////////////////////////////
  /// Invoke this on EOL. Writes out space backspace, to wrap to the next line.
  /// Otherwise, we stay on the same line and the input gets pushed upwards.
  void
  TerminalDisplayUnix::ActOnEOL() {
    if (!IsTTY()) return;
    WriteRawString(" \b", 2);
    //MoveUp();
  }

  void
  TerminalDisplayUnix::Attach() {
    // set to noecho
    if (fIsAttached) return;
    syncOut(fOutputID);
    TerminalConfigUnix::Get().Attach();
    fWritePos = Pos();
    fWriteLen = 0;
    fIsAttached = true;
  }

  void
  TerminalDisplayUnix::Detach() {
    if (!fIsAttached) return;
    syncOut(fOutputID);
    TerminalConfigUnix::Get().Detach();
    TerminalDisplay::Detach();
    fIsAttached = false;
  }

  int
  TerminalDisplayUnix::GetClosestColorIdx16(const Color& C) {
    int r = C.fR;
    int g = C.fG;
    int b = C.fB;
    int sum = r + g + b;
    r = r > sum / 4;
    g = g > sum / 4;
    b = b > sum / 4;

    // ANSI:
    return r + (g * 2) + (b * 4);
    // ! ANSI:
    // return (r * 4) + (g * 2) + b;
  }

  int
  TerminalDisplayUnix::GetClosestColorIdx256(const Color& C) {
    static unsigned char rgb256[256][3] = {{0}};
    if (rgb256[0][0] == 0) {
      InitRGB256(rgb256);
    }

    // Find the closest index.
    // A: the closest color match (square of geometric distance in RGB)
    // B: the closest brightness match
    // Treat them equally, which suppresses differences
    // in color due to squared distance.

    // start with black:
    int idx = 0;
    unsigned int r = C.fR;
    unsigned int g = C.fG;
    unsigned int b = C.fB;
    unsigned int graylvl = (r + g + b)/3;
    long mindelta = (r*r + g*g + b*b) + graylvl;
    if (mindelta) {
      for (unsigned int i = 0; i < 256; ++i) {
        long delta = (rgb256[i][0] + rgb256[i][1] + rgb256[i][2])/3 - graylvl;
        if (delta < 0) delta = -delta;
        delta += (r-rgb256[i][0])*(r-rgb256[i][0]) +
        (g-rgb256[i][1])*(g-rgb256[i][1]) +
        (b-rgb256[i][2])*(b-rgb256[i][2]);

        if (delta < mindelta) {
          mindelta = delta;
          idx = i;
          if (mindelta == 0) break;
        }
      }
    }
    return idx;
  }

}

#endif // #ifndef _WIN32
<|endoftext|>


<commit_before>// CommonFunc.cpp -- source file
/*
 * Author: Ivan Chapkailo (septimomend)
 * Date:   02.07.2017
 *
 * © 2017 Ivan Chapkailo. All rights reserved
 * e-mail: chapkailo.ivan@gmail.com
 */

#include "stdafx.h"
#include "CommonFunc.h"

Common::Common()
{
  m_All = tml.getAllControllerObj();
  m_pCnfg = m_All->getConfigObj();
}

Common::Common(AllControllers* all) : m_pCnfg(all->getConfigObj())
{
}

void Common::openFile(char *filename)
{
  // TODO
}

void Common::save()
{
  // TODO
}

void Common::find()
{
  // TODO
}

void Common::drawRows(Adbfr* abfr);
{
  // TODO
}

void Common::drawStatusBar(Adbfr* abfr)
{
  // TODO
}

void Common::drawMessageBar(Adbfr* abfr)
{
  // TODO
}

void Common::scrolling()
{
  // TODO
}

void Common::statusMsg(const char *fmt, ...)
{
  va_list arg;         // for unknown number of parameters
  va_start(arg, fmt);  // initialize arg
  vsnprintf(cnfg.statusMessage, sizeof(cnfg.statusMessage), fmt, arg); // output parameters to statusMessage
  va_end(arg); // end
  cnfg.statusMessageTime = time(NULL); // gets time
}

void Common::updateScreen()
{
  scrolling();

  m_abfr = ADBFR_IMPL; // implement to NULL

  m_abfr.reallocateBfr("\x1b[?25l", 6); // reallocate data
  m_abfr.reallocateBfr("\x1b[H", 3);    // reallocate data

  /*
   * draw rows, message bar and status bar
   */
  drawRows(&m_abfr);
  drawStatusBar(&m_abfr);
  drawMessageBar(&m_abfr);

  /*
   * write to buff cursor | position
   */
  char buff[32];
  snprintf(buff, sizeof(buff), "\x1b[%d;%dH", (m_pCnfg->configY - m_pCnfg->disableRow) + 1, (m_pCnfg->rowX - m_pCnfg->disableClr) + 1);
  m_abfr.reallocateBfr(buff, strlen(buff));

  m_abfr.reallocateBfr("\x1b[?25h", 6);

  /*
   * update screen
   */
  write(STDOUT_FILENO, ab.b, ab.len);
  m_abfr.freeBfr(); // free memory
}

char* Common::callPrompt(char *prompt, void (*callback)(char*, int))
{
  size_t buffsize = 128;
  char* bfr = malloc(buffsize); // allocate memory

  size_t bufflen = 0;           // lenght
  bfr[0] = '\0';

  while (1)
  {
    statusMsg(prompt, bfr); // set prompt
    updateScreen();         // and update screen

    int key = tml.whatKey();  // read key

    if (key == DELETE_KEY || key == CTRL_KEY('h') || key == BACKSPACE)
    {
      if (bufflen != 0)         // if buffer is not empty
        bfr[--bufflen] = '\0';  // set end of row
    }
    else if (key == '\x1b')     // if this is ESC
    {
      statusMsg("");          // erase
      if (callback)           // if callback is not NULL
        callback(bfr, key);   // call func for callback which pointed by callback()
      free(bfr);              // free memory
      return NULL;            // and cancel
    }
    else if (key == '\r')     // if carriage return (move the cursor at the start of the line)
    {
      if (bufflen != 0)       // and bufflen is not empty
      {
        statusMsg("");        // clean message
        if (callback)
          callback(bfr, key); // and get callback
        return bfr;           // returning of buffer
      }
    }
    else if (!iscntrl(key) && key < 128) // checks, whether the argument, transmitted via the parameter сharacter, control character
    {
      /*
       * reallocation of buffer if needs
       */
      if (bufflen == buffsize - 1)
      {
        buffsize *= 2;
        bfr = realloc(bfr, buffsize);
      }
      bfr[bufflen++] = key; // write this key to buffer
      bfr[bufflen] = '\0';  // and end of row
    }

    if (callback)
      callback(bfr, key);   // call of callback
  }
}

void Common::moveCursor(int key)
{
  // instancing RowController
  // if empty - to zero position, else to the end of row
  //
  RowController* pRowctrl = (m_pCnfg->configY >= m_pCnfg->rowCount) ? NULL : &m_pCnfg->pRowObj[m_pCnfg->configY];

  switch (key)
  {
    case ARROW_LEFT:
      if (m_pCnfg->configX != 0)                                    // if horizontal position isn't zero
      {
        m_pCnfg->configX--;                                         // move left
      }
      else if (m_pCnfg->configY > 0)                                // else if there is at least 1 row
      {
        m_pCnfg->configY--;                                         // move to that row
        m_pCnfg->configX = m_pCnfg->pRowObj[m_pCnfg->configY].size; // and to the end of that row
      }
      break;
    case ARROW_RIGHT:
      if (pRowctrl && m_pCnfg->configX < pRowctrl->size)            // if there is row and if cursor is not in the end of row
      {
        m_pCnfg->configX++;                                         // move cursor right along of row
      }
      else if (pRowctrl && m_pCnfg->configX == pRowctrl->size)      // if there is row and cursor in the end of this row
      {
        m_pCnfg->configY++;                                         // move to next row
        E.cx = 0;                                                   // on zero position
      }
      break;
    case ARROW_UP:
      if (m_pCnfg->configY != 0)                                    // if there is at least 1 row
      {
        m_pCnfg->configY--;                                         // move up
      }
      break;
    case ARROW_DOWN:
      if (m_pCnfg->configY < m_pCnfg->rowCount)                     // if cursor is not on last row
      {
        m_pCnfg->configY++;                                         // move down
      }
      break;
  }
}

void Common::processingKeypress()
{
  static int sQuitCounter = EDITORRMEND_QUIT_COUNTER;                // counter clicking for exit

  int key = whatKey();                                               // read key

  switch (key)
  {
    case '\r':                                                       // if carriage return (Enter key)
      setNewline();                                                   // set newline
      break;

    case CTRL_KEY('q'):
      if (m_pCnfg->smear && sQuitCounter > 0)                        // if there is any changes and counter > 0
      {
        statusMsg("! File was changed and unsaved and data can be lost after exiting. "
                  "Press Ctrl-Q %d more times to exit.", sQuitCounter);
        sQuitCounter--;                                              // counter decrement
        return;
      }
      write(STDOUT_FILENO, "\x1b[2J", 4);
      write(STDOUT_FILENO, "\x1b[H", 3);
      exit(0);
      break;

    case CTRL_KEY('s'):
      save();                                                       // TODO: save changes
      break;

    case HOME_KEY:
    m_pCnfg->configX = 0;                                           // to the row beginning
      break;

    case END_KEY:
      if (m_pCnfg->configY < m_pCnfg->rowCount)                     // if not last row
        m_pCnfg->configX = m_pCnfg->pRowObj[m_pCnfg->configY].size; // to the end of row
      break;

    case CTRL_KEY('f'):
      find();                                                       // find func
      break;

    case BACKSPACE:
    case CTRL_KEY('h'):
    case DELETE_KEY:
      if (key == DELETE_KEY)
        moveCursor(ARROW_RIGHT);                                    // move cursor right
      deleteChar();                                                 // delete char
      break;

    // page up/down
    //
    case PAGE_UP:
    case PAGE_DOWN:
      {
        if (key == PAGE_UP)
        {
          m_pCnfg->configY = m_pCnfg->disableRow;                    // move page up
        }
        else if (key == PAGE_DOWN)
        {
          m_pCnfg->configY = m_pCnfg->disableRow + m_pCnfg->enableRow - 1; // move page down
          if (m_pCnfg->configY > m_pCnfg->rowCount)
            m_pCnfg->configY = m_pCnfg->rowCount;
        }

        int times = m_pCnfg->enableRow;
        while (times--)
          moveCursor(key == PAGE_UP ? ARROW_UP : ARROW_DOWN);
      }
      break;

    case ARROW_UP:
    case ARROW_DOWN:
    case ARROW_LEFT:
    case ARROW_RIGHT:
      moveCursor(key);
      break;

    case CTRL_KEY('l'):
    case '\x1b':
      break;

    default:
      setChar(key);   // just write chars
      break;
  }

  sQuitCounter = EDITORRMEND_QUIT_COUNTER;
}
<commit_msg>openFile() function is defined<commit_after>// CommonFunc.cpp -- source file
/*
 * Author: Ivan Chapkailo (septimomend)
 * Date:   02.07.2017
 *
 * © 2017 Ivan Chapkailo. All rights reserved
 * e-mail: chapkailo.ivan@gmail.com
 */

#include "stdafx.h"
#include "CommonFunc.h"

Common::Common()
{
  m_All = tml.getAllControllerObj();
  m_pCnfg = m_All->getConfigObj();
}

Common::Common(AllControllers* all) : m_pCnfg(all->getConfigObj())
{
}

void Common::openFile(char *filename)
{
  free(m_pCnfg->pFilename);                                                       // free pFilename becouse strdup uses malloc and in next func
                                                                                // call need to free memory
  m_pCnfg->pFilename = strdup(filename);                                          // duplicate filename to pFilename

  m_All->pickSyntaxClr();

  FILE* fln = fopen(filename, "r");                                                // open file foe reading
  if (!fln)                                                                        // if can't to open file
    tml.emergencyDestruction("fopen");                                            // forced closure

  char* pStr = NULL;
  size_t strUSZ = 0;                                                              // size
  ssize_t strSSZ;                                                                 // signed size
  while ((strSSZ = getline(&pStr, &strUSZ, fln)) != -1)                            // while strUSZ size of pStr that reads from file fp
  {
    while (strSSZ > 0 && (pStr[strSSZ - 1] == '\n' || pStr[strSSZ - 1] == '\r'))  // if this is end of line
      strSSZ--;                                                                   // decrease line size
    m_pCnfg->setRow(m_pCnfg->rowCount, pStr, strSSZ);                             // set rows from file
  }
  free(pStr);
  fclose(fln);                                                                    // close file
  m_pCnfg->smear = 0;                                                             // no changes in now opened file
}

void Common::save()
{
  // TODO
}

void Common::find()
{
  // TODO
}

void Common::drawRows(Adbfr* abfr);
{
  // TODO
}

void Common::drawStatusBar(Adbfr* abfr)
{
  // TODO
}

void Common::drawMessageBar(Adbfr* abfr)
{
  // TODO
}

void Common::scrolling()
{
  // TODO
}

void Common::statusMsg(const char *fmt, ...)
{
  va_list arg;         // for unknown number of parameters
  va_start(arg, fmt);  // initialize arg
  vsnprintf(cnfg.statusMessage, sizeof(cnfg.statusMessage), fmt, arg); // output parameters to statusMessage
  va_end(arg); // end
  cnfg.statusMessageTime = time(NULL); // gets time
}

void Common::updateScreen()
{
  scrolling();

  m_abfr = ADBFR_IMPL; // implement to NULL

  m_abfr.reallocateBfr("\x1b[?25l", 6); // reallocate data
  m_abfr.reallocateBfr("\x1b[H", 3);    // reallocate data

  /*
   * draw rows, message bar and status bar
   */
  drawRows(&m_abfr);
  drawStatusBar(&m_abfr);
  drawMessageBar(&m_abfr);

  /*
   * write to buff cursor | position
   */
  char buff[32];
  snprintf(buff, sizeof(buff), "\x1b[%d;%dH", (m_pCnfg->configY - m_pCnfg->disableRow) + 1, (m_pCnfg->rowX - m_pCnfg->disableClr) + 1);
  m_abfr.reallocateBfr(buff, strlen(buff));

  m_abfr.reallocateBfr("\x1b[?25h", 6);

  /*
   * update screen
   */
  write(STDOUT_FILENO, ab.b, ab.len);
  m_abfr.freeBfr(); // free memory
}

char* Common::callPrompt(char *prompt, void (*callback)(char*, int))
{
  size_t buffsize = 128;
  char* bfr = malloc(buffsize); // allocate memory

  size_t bufflen = 0;           // lenght
  bfr[0] = '\0';

  while (1)
  {
    statusMsg(prompt, bfr); // set prompt
    updateScreen();         // and update screen

    int key = tml.whatKey();  // read key

    if (key == DELETE_KEY || key == CTRL_KEY('h') || key == BACKSPACE)
    {
      if (bufflen != 0)         // if buffer is not empty
        bfr[--bufflen] = '\0';  // set end of row
    }
    else if (key == '\x1b')     // if this is ESC
    {
      statusMsg("");          // erase
      if (callback)           // if callback is not NULL
        callback(bfr, key);   // call func for callback which pointed by callback()
      free(bfr);              // free memory
      return NULL;            // and cancel
    }
    else if (key == '\r')     // if carriage return (move the cursor at the start of the line)
    {
      if (bufflen != 0)       // and bufflen is not empty
      {
        statusMsg("");        // clean message
        if (callback)
          callback(bfr, key); // and get callback
        return bfr;           // returning of buffer
      }
    }
    else if (!iscntrl(key) && key < 128) // checks, whether the argument, transmitted via the parameter сharacter, control character
    {
      /*
       * reallocation of buffer if needs
       */
      if (bufflen == buffsize - 1)
      {
        buffsize *= 2;
        bfr = realloc(bfr, buffsize);
      }
      bfr[bufflen++] = key; // write this key to buffer
      bfr[bufflen] = '\0';  // and end of row
    }

    if (callback)
      callback(bfr, key);   // call of callback
  }
}

void Common::moveCursor(int key)
{
  // instancing RowController
  // if empty - to zero position, else to the end of row
  //
  RowController* pRowctrl = (m_pCnfg->configY >= m_pCnfg->rowCount) ? NULL : &m_pCnfg->pRowObj[m_pCnfg->configY];

  switch (key)
  {
    case ARROW_LEFT:
      if (m_pCnfg->configX != 0)                                    // if horizontal position isn't zero
      {
        m_pCnfg->configX--;                                         // move left
      }
      else if (m_pCnfg->configY > 0)                                // else if there is at least 1 row
      {
        m_pCnfg->configY--;                                         // move to that row
        m_pCnfg->configX = m_pCnfg->pRowObj[m_pCnfg->configY].size; // and to the end of that row
      }
      break;
    case ARROW_RIGHT:
      if (pRowctrl && m_pCnfg->configX < pRowctrl->size)            // if there is row and if cursor is not in the end of row
      {
        m_pCnfg->configX++;                                         // move cursor right along of row
      }
      else if (pRowctrl && m_pCnfg->configX == pRowctrl->size)      // if there is row and cursor in the end of this row
      {
        m_pCnfg->configY++;                                         // move to next row
        E.cx = 0;                                                   // on zero position
      }
      break;
    case ARROW_UP:
      if (m_pCnfg->configY != 0)                                    // if there is at least 1 row
      {
        m_pCnfg->configY--;                                         // move up
      }
      break;
    case ARROW_DOWN:
      if (m_pCnfg->configY < m_pCnfg->rowCount)                     // if cursor is not on last row
      {
        m_pCnfg->configY++;                                         // move down
      }
      break;
  }
}

void Common::processingKeypress()
{
  static int sQuitCounter = EDITORRMEND_QUIT_COUNTER;                // counter clicking for exit

  int key = whatKey();                                               // read key

  switch (key)
  {
    case '\r':                                                       // if carriage return (Enter key)
      setNewline();                                                   // set newline
      break;

    case CTRL_KEY('q'):
      if (m_pCnfg->smear && sQuitCounter > 0)                        // if there is any changes and counter > 0
      {
        statusMsg("! File was changed and unsaved and data can be lost after exiting. "
                  "Press Ctrl-Q %d more times to exit.", sQuitCounter);
        sQuitCounter--;                                              // counter decrement
        return;
      }
      write(STDOUT_FILENO, "\x1b[2J", 4);
      write(STDOUT_FILENO, "\x1b[H", 3);
      exit(0);
      break;

    case CTRL_KEY('s'):
      save();                                                       // TODO: save changes
      break;

    case HOME_KEY:
    m_pCnfg->configX = 0;                                           // to the row beginning
      break;

    case END_KEY:
      if (m_pCnfg->configY < m_pCnfg->rowCount)                     // if not last row
        m_pCnfg->configX = m_pCnfg->pRowObj[m_pCnfg->configY].size; // to the end of row
      break;

    case CTRL_KEY('f'):
      find();                                                       // find func
      break;

    case BACKSPACE:
    case CTRL_KEY('h'):
    case DELETE_KEY:
      if (key == DELETE_KEY)
        moveCursor(ARROW_RIGHT);                                    // move cursor right
      deleteChar();                                                 // delete char
      break;

    // page up/down
    //
    case PAGE_UP:
    case PAGE_DOWN:
      {
        if (key == PAGE_UP)
        {
          m_pCnfg->configY = m_pCnfg->disableRow;                    // move page up
        }
        else if (key == PAGE_DOWN)
        {
          m_pCnfg->configY = m_pCnfg->disableRow + m_pCnfg->enableRow - 1; // move page down
          if (m_pCnfg->configY > m_pCnfg->rowCount)
            m_pCnfg->configY = m_pCnfg->rowCount;
        }

        int times = m_pCnfg->enableRow;
        while (times--)
          moveCursor(key == PAGE_UP ? ARROW_UP : ARROW_DOWN);
      }
      break;

    case ARROW_UP:
    case ARROW_DOWN:
    case ARROW_LEFT:
    case ARROW_RIGHT:
      moveCursor(key);
      break;

    case CTRL_KEY('l'):
    case '\x1b':
      break;

    default:
      setChar(key);   // just write chars
      break;
  }

  sQuitCounter = EDITORRMEND_QUIT_COUNTER;
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016 DeepCortex GmbH <legal@eventql.io>
 * Authors:
 *   - Paul Asmuth <paul@eventql.io>
 *   - Laura Schlimmer <laura@eventql.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <algorithm>
#include <eventql/sql/statements/select/orderby.h>
#include <eventql/sql/expressions/boolean.h>
#include <eventql/sql/runtime/runtime.h>
#include <eventql/util/inspect.h>

namespace csql {

OrderByExpression::OrderByExpression(
    Transaction* txn,
    ExecutionContext* execution_context,
    Vector<SortExpr> sort_specs,
    ScopedPtr<TableExpression> input) :
    txn_(txn),
    execution_context_(execution_context),
    sort_specs_(std::move(sort_specs)),
    input_(std::move(input)),
    num_rows_(0),
    pos_(0),
    cnt_(0) {
  if (sort_specs_.size() == 0) {
    RAISE(kIllegalArgumentError, "can't execute ORDER BY: no sort specs");
  }

  execution_context_->incrementNumTasks();
}

ReturnCode OrderByExpression::execute() {
  auto rc = input_->execute();
  if (!rc.isSuccess()) {
    return rc;
  }

  execution_context_->incrementNumTasksRunning();

  Vector<SVector> input_cols;
  for (size_t i = 0; i < input_->getColumnCount(); ++i) {
    input_cols.emplace_back(input_->getColumnType(i));
  }

  for (;;) {
    for (auto& c : input_cols) {
      c.clear();
    }

    size_t nrecords = 0;
    {
      auto rc = input_->nextBatch(input_cols.data(), &nrecords);
      if (!rc.isSuccess()) {
        RAISE(kRuntimeError, rc.getMessage());
      }
    }

    if (nrecords == 0) {
      break;
    }

    {
      auto rc = txn_->triggerHeartbeat();
      if (!rc.isSuccess()) {
        RAISE(kRuntimeError, rc.getMessage());
      }
    }

    Vector<void*> input_col_cursor;
    for (const auto& c : input_cols) {
      input_col_cursor.emplace_back((void*) c.getData());
    }

    for (size_t n = 0; n < nrecords; n++) {
      rows_.emplace_back();
      auto& row = rows_.back();

      for (size_t i = 0; i < input_->getColumnCount(); ++i) {
        row.emplace_back(input_->getColumnType(i));
        row[i].copyFrom(input_col_cursor[i]);
      }
    }
  }

  num_rows_ = rows_.size();

  std::sort(
      rows_.begin(),
      rows_.end(),
      [this] (const Vector<SValue>& left, const Vector<SValue>& right) -> bool {
    if (++cnt_ % 4096 == 0) {
      auto rc = txn_->triggerHeartbeat();
      if (!rc.isSuccess()) {
        RAISE(kRuntimeError, rc.getMessage());
      }
    }

    for (const auto& sort : sort_specs_) {
      VM::evaluateBoxed(
          txn_,
          sort.expr.program(),
          sort.expr.program()->method_call,
          &vm_stack_,
          nullptr,
          left.size(),
          left.data());

      VM::evaluateBoxed(
          txn_,
          sort.expr.program(),
          sort.expr.program()->method_call,
          &vm_stack_,
          nullptr,
          right.size(),
          right.data());

      std::array<SValue, 2> args = {
          sort.expr.program()->return_type,
          sort.expr.program()->return_type };

      popBoxed(&vm_stack_, &args[0]);
      popBoxed(&vm_stack_, &args[1]);

      SValue res(false);
      expressions::eqExpr(Transaction::get(txn_), 2, args.data(), &res);
      if (res.getBool()) {
        continue;
      }

      if (sort.descending) {
        expressions::gtExpr(Transaction::get(txn_), 2, args.data(), &res);
      } else {
        expressions::ltExpr(Transaction::get(txn_), 2, args.data(), &res);
      }

      return res.getBool();
    }

    /* all dimensions equal */
    return false;
  });

  return ReturnCode::success();
}

ReturnCode OrderByExpression::nextBatch(
    SVector* output,
    size_t* nrecords) {
  *nrecords = 0;

  if (pos_ < num_rows_) {
    auto batch_len = std::min(num_rows_ - pos_, kOutputBatchSize);
    auto ncols = input_->getColumnCount();

    for (size_t n = 0; n < batch_len; ++n) {
      for (size_t i = 0; i < ncols; ++i) {
        output[i].append(
            rows_[pos_][i].getData(),
            rows_[pos_][i].getSize());
      }
    }

    *nrecords += batch_len;
    pos_ += batch_len;
    if (pos_ == num_rows_) {
      execution_context_->incrementNumTasksCompleted();
    }
  }

  return ReturnCode::success();
}

size_t OrderByExpression::getColumnCount() const {
  return input_->getColumnCount();
}

SType OrderByExpression::getColumnType(size_t idx) const {
  return input_->getColumnType(idx);
}

} // namespace csql
<commit_msg>fixed include<commit_after>/**
 * Copyright (c) 2016 DeepCortex GmbH <legal@eventql.io>
 * Authors:
 *   - Paul Asmuth <paul@eventql.io>
 *   - Laura Schlimmer <laura@eventql.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <algorithm>
#include <array>
#include <eventql/sql/statements/select/orderby.h>
#include <eventql/sql/expressions/boolean.h>
#include <eventql/sql/runtime/runtime.h>
#include <eventql/util/inspect.h>

namespace csql {

OrderByExpression::OrderByExpression(
    Transaction* txn,
    ExecutionContext* execution_context,
    Vector<SortExpr> sort_specs,
    ScopedPtr<TableExpression> input) :
    txn_(txn),
    execution_context_(execution_context),
    sort_specs_(std::move(sort_specs)),
    input_(std::move(input)),
    num_rows_(0),
    pos_(0),
    cnt_(0) {
  if (sort_specs_.size() == 0) {
    RAISE(kIllegalArgumentError, "can't execute ORDER BY: no sort specs");
  }

  execution_context_->incrementNumTasks();
}

ReturnCode OrderByExpression::execute() {
  auto rc = input_->execute();
  if (!rc.isSuccess()) {
    return rc;
  }

  execution_context_->incrementNumTasksRunning();

  Vector<SVector> input_cols;
  for (size_t i = 0; i < input_->getColumnCount(); ++i) {
    input_cols.emplace_back(input_->getColumnType(i));
  }

  for (;;) {
    for (auto& c : input_cols) {
      c.clear();
    }

    size_t nrecords = 0;
    {
      auto rc = input_->nextBatch(input_cols.data(), &nrecords);
      if (!rc.isSuccess()) {
        RAISE(kRuntimeError, rc.getMessage());
      }
    }

    if (nrecords == 0) {
      break;
    }

    {
      auto rc = txn_->triggerHeartbeat();
      if (!rc.isSuccess()) {
        RAISE(kRuntimeError, rc.getMessage());
      }
    }

    Vector<void*> input_col_cursor;
    for (const auto& c : input_cols) {
      input_col_cursor.emplace_back((void*) c.getData());
    }

    for (size_t n = 0; n < nrecords; n++) {
      rows_.emplace_back();
      auto& row = rows_.back();

      for (size_t i = 0; i < input_->getColumnCount(); ++i) {
        row.emplace_back(input_->getColumnType(i));
        row[i].copyFrom(input_col_cursor[i]);
      }
    }
  }

  num_rows_ = rows_.size();

  std::sort(
      rows_.begin(),
      rows_.end(),
      [this] (const Vector<SValue>& left, const Vector<SValue>& right) -> bool {
    if (++cnt_ % 4096 == 0) {
      auto rc = txn_->triggerHeartbeat();
      if (!rc.isSuccess()) {
        RAISE(kRuntimeError, rc.getMessage());
      }
    }

    for (const auto& sort : sort_specs_) {
      VM::evaluateBoxed(
          txn_,
          sort.expr.program(),
          sort.expr.program()->method_call,
          &vm_stack_,
          nullptr,
          left.size(),
          left.data());

      VM::evaluateBoxed(
          txn_,
          sort.expr.program(),
          sort.expr.program()->method_call,
          &vm_stack_,
          nullptr,
          right.size(),
          right.data());

      std::array<SValue, 2> args = {
          sort.expr.program()->return_type,
          sort.expr.program()->return_type };

      popBoxed(&vm_stack_, &args[0]);
      popBoxed(&vm_stack_, &args[1]);

      SValue res(false);
      expressions::eqExpr(Transaction::get(txn_), 2, args.data(), &res);
      if (res.getBool()) {
        continue;
      }

      if (sort.descending) {
        expressions::gtExpr(Transaction::get(txn_), 2, args.data(), &res);
      } else {
        expressions::ltExpr(Transaction::get(txn_), 2, args.data(), &res);
      }

      return res.getBool();
    }

    /* all dimensions equal */
    return false;
  });

  return ReturnCode::success();
}

ReturnCode OrderByExpression::nextBatch(
    SVector* output,
    size_t* nrecords) {
  *nrecords = 0;

  if (pos_ < num_rows_) {
    auto batch_len = std::min(num_rows_ - pos_, kOutputBatchSize);
    auto ncols = input_->getColumnCount();

    for (size_t n = 0; n < batch_len; ++n) {
      for (size_t i = 0; i < ncols; ++i) {
        output[i].append(
            rows_[pos_][i].getData(),
            rows_[pos_][i].getSize());
      }
    }

    *nrecords += batch_len;
    pos_ += batch_len;
    if (pos_ == num_rows_) {
      execution_context_->incrementNumTasksCompleted();
    }
  }

  return ReturnCode::success();
}

size_t OrderByExpression::getColumnCount() const {
  return input_->getColumnCount();
}

SType OrderByExpression::getColumnType(size_t idx) const {
  return input_->getColumnType(idx);
}

} // namespace csql
<|endoftext|>


<commit_before>/*
This file is picked from project testa [https://github.com/TimeExceed/testa.git]
Copyright (c) 2017, Taoda (tyf00@aliyun.com)
All rights reserved.

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

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

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

* Neither the name of the {organization} nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "metaprogramming.hpp"
#include <string>
#include <deque>
#include <cstdlib>

#if __cplusplus < 201103L
#include <tr1/tuple>
#include <stdint.h>
#else
#include <tuple>
#include <cstdint>
#endif

namespace pp {
namespace impl {

template<class T, void (T::*)(std::string&) const>
struct IsPrettyPrintable
{
    typedef void Type;
};

template<class T>
struct PrettyPrinter<
    T,
    typename IsPrettyPrintable<T, &T::prettyPrint>::Type>
{
    void operator()(std::string& out, const T& x) const
    {
        x.prettyPrint(out);
    }
};

template<>
struct PrettyPrinter<bool, void>
{
    void operator()(std::string& out, bool x) const
    {
        static const char kTrue[] = "true";
        static const char kFalse[] = "false";
        if (x) {
            out.append(kTrue, sizeof(kTrue) - 1);
        } else {
            out.append(kFalse, sizeof(kFalse) - 1);
        }
    };
};

inline void toHex(std::string& out, uint8_t x)
{
    static const char kAlphabet[] = "0123456789ABCDEF";
    if (x > 15) {
        ::abort();
    }
    out.push_back(kAlphabet[x]);
}

struct Char
{
    static void p(std::string& out, char x)
    {
        uint8_t xx = x;
        if (xx >= 32 && xx <= 127) {
            if (x == '\'') {
                out.push_back('\\');
                out.push_back('\'');
            } else if (x == '"') {
                out.push_back('\\');
                out.push_back('"');
            } else {
                out.push_back(x);
            }
        } else {
            out.push_back('\\');
            out.push_back('x');
            toHex(out, xx >> 4);
            toHex(out, xx & 0xF);
        }
    };
};

template<>
struct PrettyPrinter<char, void>
{
    void operator()(std::string& out, char x) const
    {
        out.push_back('\'');
        Char::p(out, x);
        out.push_back('\'');
    };
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<mp::IsInteger<T>::value && mp::IsUnsigned<T>::value>::Type>
{
    void operator()(std::string& out, T x) const
    {
        if (x == 0) {
            out.push_back('0');
        } else {
            std::deque<uint8_t> xs;
            for(; x > 0; x /= 10) {
                xs.push_back(x % 10);
            }
            for(; !xs.empty(); xs.pop_back()) {
                out.push_back('0' + xs.back());
            }
        }
    };
};

template<>
struct PrettyPrinter<std::string, void>
{
    void operator()(std::string& out, const std::string& x) const
    {
        out.push_back('\"');
        for(std::string::const_iterator i = x.begin(); i != x.end(); ++i) {
            Char::p(out, *i);
        }
        out.push_back('\"');
    }
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<mp::IsInteger<T>::value && mp::IsSigned<T>::value>::Type>
{
    void operator()(std::string& out, T x) const
    {
        typename mp::MakeUnsigned<T>::Type y = x >= 0 ? x : -x;
        if (x < 0) {
            out.push_back('-');
        }
        pp::prettyPrint(out, y);
    };
};

struct Floating
{
    static void p(std::string&, double);
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<mp::IsFloatingPoint<T>::value>::Type>
{
    void operator()(std::string& out, T x) const
    {
        Floating::p(out, x);
    }
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<
        mp::IsSeq<T>::value
        && !mp::IsAssociative<T>::value
        && !mp::IsSame<T, std::string>::value>::Type>
{
    void operator()(std::string& out, const T& xs) const
    {
        if (xs.empty()) {
            out.append("[]");
            return;
        }
        out.push_back('[');
        typename T::const_iterator it = xs.begin();
        prettyPrint(out, *it);
        for(++it; it != xs.end(); ++it) {
            out.push_back(',');
            prettyPrint(out, *it);
        }
        out.push_back(']');
    }
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<mp::IsAssociative<T>::value>::Type>
{
    void operator()(std::string& out, const T& xs) const
    {
        if (xs.empty()) {
            out.append("{}");
            return;
        }
        out.push_back('{');
        typename T::const_iterator it = xs.begin();
        prettyPrint(out, it->first);
        out.push_back(':');
        prettyPrint(out, it->second);
        for(++it; it != xs.end(); ++it) {
            out.push_back(',');
            prettyPrint(out, it->first);
            out.push_back(':');
            prettyPrint(out, it->second);
        }
        out.push_back('}');
    }
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<mp::IsSmartPtr<T>::value>::Type>
{
    void operator()(std::string& out, const T& ptr) const
    {
        if (ptr.get() == NULL) {
            out.append("null");
        } else {
            pp::prettyPrint(out, *ptr);
        }
    }
};

#if __cplusplus < 201103L
template<class T>
struct _TupleSize
{
    static const std::size_t value = std::tr1::tuple_size<T>::value;
};
template<class T, std::size_t n>
const typename std::tr1::tuple_element<n, T>::type& _getTuple(const T& xs)
{
    return std::tr1::get<n>(xs);
}
#else
template<class T>
struct _TupleSize
{
    static const std::size_t value = std::tuple_size<T>::value;
};
template<class T, std::size_t n>
const typename std::tuple_element<n, T>::type& _getTuple(const T& xs)
{
    return std::get<n>(xs);
}
#endif

template<class T, std::size_t idx, bool end>
struct _TuplePrettyPrint
{
    void operator()(std::string& out, const T& xs) const
    {
        pp::prettyPrint(out, _getTuple<T, idx>(xs));
        if (idx + 1 == _TupleSize<T>::value) {
            return;
        }
        out.push_back(',');
        _TuplePrettyPrint<
            T,
            idx + 1,
            idx + 1 == _TupleSize<T>::value> p;
        p(out, xs);
    }
};

template<class T, std::size_t idx>
struct _TuplePrettyPrint<T, idx, true>
{
    void operator()(std::string& out, const T& xs) const
    {}
};

#if __cplusplus < 201103L
template<std::size_t n>
struct __TupleSize
{
    static const bool value = (n >= 0);
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<__TupleSize<std::tr1::tuple_size<T>::value>::value>::Type>
{
    void operator()(std::string& out, const T& xs) const
    {
        out.push_back('(');
        _TuplePrettyPrint<T, 0, std::tr1::tuple_size<T>::value == 0> p;
        p(out, xs);
        out.push_back(')');
    }

};
#else
template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIfExists<typename std::tuple_size<T>::value_type>::Type>
{
    void operator()(std::string& out, const T& xs) const
    {
        out.push_back('(');
        _TuplePrettyPrint<T, 0, std::tuple_size<T>::value == 0> p;
        p(out, xs);
        out.push_back(')');
    }

};
#endif

template<int n>
struct PrettyPrinter<const char[n], void>
{
    void operator()(std::string& out, const char* cs) const
    {
        out.append(cs, n);
    }
};

template<>
struct PrettyPrinter<const char*, void>
{
    void operator()(std::string& out, const char* cs) const
    {
        out.append(cs);
    }
};

} // namespace impl
} // namespace pp
<commit_msg>fix a bug on handling c++ string literals<commit_after>/*
This file is picked from project testa [https://github.com/TimeExceed/testa.git]
Copyright (c) 2017, Taoda (tyf00@aliyun.com)
All rights reserved.

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

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

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

* Neither the name of the {organization} nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "metaprogramming.hpp"
#include <string>
#include <deque>
#include <cstdlib>

#if __cplusplus < 201103L
#include <tr1/tuple>
#include <stdint.h>
#else
#include <tuple>
#include <cstdint>
#endif

namespace pp {
namespace impl {

template<class T, void (T::*)(std::string&) const>
struct IsPrettyPrintable
{
    typedef void Type;
};

template<class T>
struct PrettyPrinter<
    T,
    typename IsPrettyPrintable<T, &T::prettyPrint>::Type>
{
    void operator()(std::string& out, const T& x) const
    {
        x.prettyPrint(out);
    }
};

template<>
struct PrettyPrinter<bool, void>
{
    void operator()(std::string& out, bool x) const
    {
        static const char kTrue[] = "true";
        static const char kFalse[] = "false";
        if (x) {
            out.append(kTrue, sizeof(kTrue) - 1);
        } else {
            out.append(kFalse, sizeof(kFalse) - 1);
        }
    };
};

inline void toHex(std::string& out, uint8_t x)
{
    static const char kAlphabet[] = "0123456789ABCDEF";
    if (x > 15) {
        ::abort();
    }
    out.push_back(kAlphabet[x]);
}

struct Char
{
    static void p(std::string& out, char x)
    {
        uint8_t xx = x;
        if (xx >= 32 && xx <= 127) {
            if (x == '\'') {
                out.push_back('\\');
                out.push_back('\'');
            } else if (x == '"') {
                out.push_back('\\');
                out.push_back('"');
            } else {
                out.push_back(x);
            }
        } else {
            out.push_back('\\');
            out.push_back('x');
            toHex(out, xx >> 4);
            toHex(out, xx & 0xF);
        }
    };
};

template<>
struct PrettyPrinter<char, void>
{
    void operator()(std::string& out, char x) const
    {
        out.push_back('\'');
        Char::p(out, x);
        out.push_back('\'');
    };
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<mp::IsInteger<T>::value && mp::IsUnsigned<T>::value>::Type>
{
    void operator()(std::string& out, T x) const
    {
        if (x == 0) {
            out.push_back('0');
        } else {
            std::deque<uint8_t> xs;
            for(; x > 0; x /= 10) {
                xs.push_back(x % 10);
            }
            for(; !xs.empty(); xs.pop_back()) {
                out.push_back('0' + xs.back());
            }
        }
    };
};

template<>
struct PrettyPrinter<std::string, void>
{
    void operator()(std::string& out, const std::string& x) const
    {
        out.push_back('\"');
        for(std::string::const_iterator i = x.begin(); i != x.end(); ++i) {
            Char::p(out, *i);
        }
        out.push_back('\"');
    }
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<mp::IsInteger<T>::value && mp::IsSigned<T>::value>::Type>
{
    void operator()(std::string& out, T x) const
    {
        typename mp::MakeUnsigned<T>::Type y = x >= 0 ? x : -x;
        if (x < 0) {
            out.push_back('-');
        }
        pp::prettyPrint(out, y);
    };
};

struct Floating
{
    static void p(std::string&, double);
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<mp::IsFloatingPoint<T>::value>::Type>
{
    void operator()(std::string& out, T x) const
    {
        Floating::p(out, x);
    }
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<
        mp::IsSeq<T>::value
        && !mp::IsAssociative<T>::value
        && !mp::IsSame<T, std::string>::value>::Type>
{
    void operator()(std::string& out, const T& xs) const
    {
        if (xs.empty()) {
            out.append("[]");
            return;
        }
        out.push_back('[');
        typename T::const_iterator it = xs.begin();
        prettyPrint(out, *it);
        for(++it; it != xs.end(); ++it) {
            out.push_back(',');
            prettyPrint(out, *it);
        }
        out.push_back(']');
    }
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<mp::IsAssociative<T>::value>::Type>
{
    void operator()(std::string& out, const T& xs) const
    {
        if (xs.empty()) {
            out.append("{}");
            return;
        }
        out.push_back('{');
        typename T::const_iterator it = xs.begin();
        prettyPrint(out, it->first);
        out.push_back(':');
        prettyPrint(out, it->second);
        for(++it; it != xs.end(); ++it) {
            out.push_back(',');
            prettyPrint(out, it->first);
            out.push_back(':');
            prettyPrint(out, it->second);
        }
        out.push_back('}');
    }
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<mp::IsSmartPtr<T>::value>::Type>
{
    void operator()(std::string& out, const T& ptr) const
    {
        if (ptr.get() == NULL) {
            out.append("null");
        } else {
            pp::prettyPrint(out, *ptr);
        }
    }
};

#if __cplusplus < 201103L
template<class T>
struct _TupleSize
{
    static const std::size_t value = std::tr1::tuple_size<T>::value;
};
template<class T, std::size_t n>
const typename std::tr1::tuple_element<n, T>::type& _getTuple(const T& xs)
{
    return std::tr1::get<n>(xs);
}
#else
template<class T>
struct _TupleSize
{
    static const std::size_t value = std::tuple_size<T>::value;
};
template<class T, std::size_t n>
const typename std::tuple_element<n, T>::type& _getTuple(const T& xs)
{
    return std::get<n>(xs);
}
#endif

template<class T, std::size_t idx, bool end>
struct _TuplePrettyPrint
{
    void operator()(std::string& out, const T& xs) const
    {
        pp::prettyPrint(out, _getTuple<T, idx>(xs));
        if (idx + 1 == _TupleSize<T>::value) {
            return;
        }
        out.push_back(',');
        _TuplePrettyPrint<
            T,
            idx + 1,
            idx + 1 == _TupleSize<T>::value> p;
        p(out, xs);
    }
};

template<class T, std::size_t idx>
struct _TuplePrettyPrint<T, idx, true>
{
    void operator()(std::string& out, const T& xs) const
    {}
};

#if __cplusplus < 201103L
template<std::size_t n>
struct __TupleSize
{
    static const bool value = (n >= 0);
};

template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIf<__TupleSize<std::tr1::tuple_size<T>::value>::value>::Type>
{
    void operator()(std::string& out, const T& xs) const
    {
        out.push_back('(');
        _TuplePrettyPrint<T, 0, std::tr1::tuple_size<T>::value == 0> p;
        p(out, xs);
        out.push_back(')');
    }

};
#else
template<class T>
struct PrettyPrinter<
    T,
    typename mp::VoidIfExists<typename std::tuple_size<T>::value_type>::Type>
{
    void operator()(std::string& out, const T& xs) const
    {
        out.push_back('(');
        _TuplePrettyPrint<T, 0, std::tuple_size<T>::value == 0> p;
        p(out, xs);
        out.push_back(')');
    }

};
#endif

template<int n>
struct PrettyPrinter<const char[n], void>
{
    void operator()(std::string& out, const char* cs) const
    {
        out.append(cs, n - 1);
    }
};

template<int n>
struct PrettyPrinter<char[n], void>
{
    void operator()(std::string& out, const char* cs) const
    {
        out.append(cs, n - 1);
    }
};

template<>
struct PrettyPrinter<const char*, void>
{
    void operator()(std::string& out, const char* cs) const
    {
        out.append(cs);
    }
};

} // namespace impl
} // namespace pp
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __EXEC_CONTEXT_HH__
#define __EXEC_CONTEXT_HH__

#include "sim/host.hh"
#include "mem/mem_req.hh"
#include "sim/serialize.hh"

// forward declaration: see functional_memory.hh
class FunctionalMemory;
class PhysicalMemory;
class BaseCPU;

#ifdef FULL_SYSTEM

#include "targetarch/alpha_memory.hh"
class MemoryController;

#include "kern/tru64/kernel_stats.hh"
#include "sim/system.hh"

#else // !FULL_SYSTEM

#include "sim/prog.hh"

#endif // FULL_SYSTEM

//
// The ExecContext object represents a functional context for
// instruction execution.  It incorporates everything required for
// architecture-level functional simulation of a single thread.
//

class ExecContext
{
  public:
    enum Status { Unallocated, Active, Suspended, Halted };

  private:
    Status _status;

  public:
    Status status() const { return _status; }

    void setStatus(Status new_status);

#ifdef FULL_SYSTEM
  public:
    KernelStats kernelStats;
#endif

  public:
    RegFile regs;	// correct-path register context

    // pointer to CPU associated with this context
    BaseCPU *cpu;

    // Index of hardware thread context on the CPU that this represents.
    int thread_num;

    // ID of this context w.r.t. the System or Process object to which
    // it belongs.  For full-system mode, this is the system CPU ID.
    int cpu_id;

#ifdef FULL_SYSTEM

    FunctionalMemory *mem;
    AlphaItb *itb;
    AlphaDtb *dtb;
    System *system;

    // the following two fields are redundant, since we can always
    // look them up through the system pointer, but we'll leave them
    // here for now for convenience
    MemoryController *memCtrl;
    PhysicalMemory *physmem;

#else
    Process *process;

    FunctionalMemory *mem;	// functional storage for process address space

    // Address space ID.  Note that this is used for TIMING cache
    // simulation only; all functional memory accesses should use
    // one of the FunctionalMemory pointers above.
    short asid;

#endif

    /*
     * number of executed instructions, for matching with syscall trace
     * points in EIO files.
     */
    Counter func_exe_insn;

    //
    // Count failed store conditionals so we can warn of apparent
    // application deadlock situations.
    unsigned storeCondFailures;

    // constructor: initialize context from given process structure
#ifdef FULL_SYSTEM
    ExecContext(BaseCPU *_cpu, int _thread_num, System *_system,
                AlphaItb *_itb, AlphaDtb *_dtb, FunctionalMemory *_dem);
#else
    ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid);
    ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem,
                int _asid);
#endif
    virtual ~ExecContext() {}

    virtual void takeOverFrom(ExecContext *oldContext);

    void regStats(const std::string &name);

    void serialize(std::ostream &os);
    void unserialize(Checkpoint *cp, const std::string &section);

#ifdef FULL_SYSTEM
    bool validInstAddr(Addr addr) { return true; }
    bool validDataAddr(Addr addr) { return true; }
    int getInstAsid() { return ITB_ASN_ASN(regs.ipr[TheISA::IPR_ITB_ASN]); }
    int getDataAsid() { return DTB_ASN_ASN(regs.ipr[TheISA::IPR_DTB_ASN]); }

    Fault translateInstReq(MemReqPtr req)
    {
        return itb->translate(req);
    }

    Fault translateDataReadReq(MemReqPtr req)
    {
        return dtb->translate(req, false);
    }

    Fault translateDataWriteReq(MemReqPtr req)
    {
        return dtb->translate(req, true);
    }

#else
    bool validInstAddr(Addr addr)
    { return process->validInstAddr(addr); }

    bool validDataAddr(Addr addr)
    { return process->validDataAddr(addr); }

    int getInstAsid() { return asid; }
    int getDataAsid() { return asid; }

    Fault dummyTranslation(MemReqPtr req)
    {
#if 0
        assert((req->vaddr >> 48 & 0xffff) == 0);
#endif

        // put the asid in the upper 16 bits of the paddr
        req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
        req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
        return No_Fault;
    }
    Fault translateInstReq(MemReqPtr req)
    {
        return dummyTranslation(req);
    }
    Fault translateDataReadReq(MemReqPtr req)
    {
        return dummyTranslation(req);
    }
    Fault translateDataWriteReq(MemReqPtr req)
    {
        return dummyTranslation(req);
    }

#endif

    template <class T>
    Fault read(MemReqPtr req, T& data)
    {
#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)
        if (req->flags & LOCKED) {
            MiscRegFile *cregs = &req->xc->regs.miscRegs;
            cregs->lock_addr = req->paddr;
            cregs->lock_flag = true;
        }
#endif
        return mem->read(req, data);
    }

    template <class T>
    Fault write(MemReqPtr req, T& data)
    {
#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)

        MiscRegFile *cregs;

        // If this is a store conditional, act appropriately
        if (req->flags & LOCKED) {
            cregs = &req->xc->regs.miscRegs;

            if (req->flags & UNCACHEABLE) {
                // Don't update result register (see stq_c in isa_desc)
                req->result = 2;
                req->xc->storeCondFailures = 0;//Needed? [RGD]
            } else {
                req->result = cregs->lock_flag;
                if (!cregs->lock_flag ||
                    ((cregs->lock_addr & ~0xf) != (req->paddr & ~0xf))) {
                    cregs->lock_flag = false;
                    if (((++req->xc->storeCondFailures) % 100000) == 0) {
                        std::cerr << "Warning: "
                                  << req->xc->storeCondFailures
                                  << " consecutive store conditional failures "
                                  << "on cpu " << req->xc->cpu_id
                                  << std::endl;
                    }
                    return No_Fault;
                }
                else req->xc->storeCondFailures = 0;
            }
        }

        // Need to clear any locked flags on other proccessors for
        // this address.  Only do this for succsful Store Conditionals
        // and all other stores (WH64?).  Unsuccessful Store
        // Conditionals would have returned above, and wouldn't fall
        // through.
        for (int i = 0; i < system->execContexts.size(); i++){
            cregs = &system->execContexts[i]->regs.miscRegs;
            if ((cregs->lock_addr & ~0xf) == (req->paddr & ~0xf)) {
                cregs->lock_flag = false;
            }
        }

#endif
        return mem->write(req, data);
    }

    virtual bool misspeculating();

    //
    // New accessors for new decoder.
    //
    uint64_t readIntReg(int reg_idx)
    {
        return regs.intRegFile[reg_idx];
    }

    float readFloatRegSingle(int reg_idx)
    {
        return (float)regs.floatRegFile.d[reg_idx];
    }

    double readFloatRegDouble(int reg_idx)
    {
        return regs.floatRegFile.d[reg_idx];
    }

    uint64_t readFloatRegInt(int reg_idx)
    {
        return regs.floatRegFile.q[reg_idx];
    }

    void setIntReg(int reg_idx, uint64_t val)
    {
        regs.intRegFile[reg_idx] = val;
    }

    void setFloatRegSingle(int reg_idx, float val)
    {
        regs.floatRegFile.d[reg_idx] = (double)val;
    }

    void setFloatRegDouble(int reg_idx, double val)
    {
        regs.floatRegFile.d[reg_idx] = val;
    }

    void setFloatRegInt(int reg_idx, uint64_t val)
    {
        regs.floatRegFile.q[reg_idx] = val;
    }

    uint64_t readPC()
    {
        return regs.pc;
    }

    void setNextPC(uint64_t val)
    {
        regs.npc = val;
    }

    uint64_t readUniq()
    {
        return regs.miscRegs.uniq;
    }

    void setUniq(uint64_t val)
    {
        regs.miscRegs.uniq = val;
    }

    uint64_t readFpcr()
    {
        return regs.miscRegs.fpcr;
    }

    void setFpcr(uint64_t val)
    {
        regs.miscRegs.fpcr = val;
    }

#ifdef FULL_SYSTEM
    uint64_t readIpr(int idx, Fault &fault);
    Fault setIpr(int idx, uint64_t val);
    Fault hwrei();
    void ev5_trap(Fault fault);
    bool simPalCheck(int palFunc);
#endif

#ifndef FULL_SYSTEM
    void syscall()
    {
        process->syscall(this);
    }
#endif
};

// for non-speculative execution context, spec_mode is always false
inline bool
ExecContext::misspeculating()
{
    return false;
}

#endif // __EXEC_CONTEXT_HH__
<commit_msg>Add some comments explaining ExecContext::Status enum.<commit_after>/*
 * Copyright (c) 2003 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __EXEC_CONTEXT_HH__
#define __EXEC_CONTEXT_HH__

#include "sim/host.hh"
#include "mem/mem_req.hh"
#include "sim/serialize.hh"

// forward declaration: see functional_memory.hh
class FunctionalMemory;
class PhysicalMemory;
class BaseCPU;

#ifdef FULL_SYSTEM

#include "targetarch/alpha_memory.hh"
class MemoryController;

#include "kern/tru64/kernel_stats.hh"
#include "sim/system.hh"

#else // !FULL_SYSTEM

#include "sim/prog.hh"

#endif // FULL_SYSTEM

//
// The ExecContext object represents a functional context for
// instruction execution.  It incorporates everything required for
// architecture-level functional simulation of a single thread.
//

class ExecContext
{
  public:
    enum Status
    {
        /// Initialized but not running yet.  All CPUs start in
        /// this state, but most transition to Active on cycle 1.
        /// In MP or SMT systems, non-primary contexts will stay
        /// in this state until a thread is assigned to them.
        Unallocated,

        /// Running.  Instructions should be executed only when
        /// the context is in this state.
        Active,

        /// Temporarily inactive.  Entered while waiting for
        /// synchronization, etc.
        Suspended,

        /// Permanently shut down.  Entered when target executes
        /// m5exit pseudo-instruction.  When all contexts enter
        /// this state, the simulation will terminate.
        Halted
    };

  private:
    Status _status;

  public:
    Status status() const { return _status; }

    void setStatus(Status new_status);

#ifdef FULL_SYSTEM
  public:
    KernelStats kernelStats;
#endif

  public:
    RegFile regs;	// correct-path register context

    // pointer to CPU associated with this context
    BaseCPU *cpu;

    // Index of hardware thread context on the CPU that this represents.
    int thread_num;

    // ID of this context w.r.t. the System or Process object to which
    // it belongs.  For full-system mode, this is the system CPU ID.
    int cpu_id;

#ifdef FULL_SYSTEM

    FunctionalMemory *mem;
    AlphaItb *itb;
    AlphaDtb *dtb;
    System *system;

    // the following two fields are redundant, since we can always
    // look them up through the system pointer, but we'll leave them
    // here for now for convenience
    MemoryController *memCtrl;
    PhysicalMemory *physmem;

#else
    Process *process;

    FunctionalMemory *mem;	// functional storage for process address space

    // Address space ID.  Note that this is used for TIMING cache
    // simulation only; all functional memory accesses should use
    // one of the FunctionalMemory pointers above.
    short asid;

#endif

    /*
     * number of executed instructions, for matching with syscall trace
     * points in EIO files.
     */
    Counter func_exe_insn;

    //
    // Count failed store conditionals so we can warn of apparent
    // application deadlock situations.
    unsigned storeCondFailures;

    // constructor: initialize context from given process structure
#ifdef FULL_SYSTEM
    ExecContext(BaseCPU *_cpu, int _thread_num, System *_system,
                AlphaItb *_itb, AlphaDtb *_dtb, FunctionalMemory *_dem);
#else
    ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid);
    ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem,
                int _asid);
#endif
    virtual ~ExecContext() {}

    virtual void takeOverFrom(ExecContext *oldContext);

    void regStats(const std::string &name);

    void serialize(std::ostream &os);
    void unserialize(Checkpoint *cp, const std::string &section);

#ifdef FULL_SYSTEM
    bool validInstAddr(Addr addr) { return true; }
    bool validDataAddr(Addr addr) { return true; }
    int getInstAsid() { return ITB_ASN_ASN(regs.ipr[TheISA::IPR_ITB_ASN]); }
    int getDataAsid() { return DTB_ASN_ASN(regs.ipr[TheISA::IPR_DTB_ASN]); }

    Fault translateInstReq(MemReqPtr req)
    {
        return itb->translate(req);
    }

    Fault translateDataReadReq(MemReqPtr req)
    {
        return dtb->translate(req, false);
    }

    Fault translateDataWriteReq(MemReqPtr req)
    {
        return dtb->translate(req, true);
    }

#else
    bool validInstAddr(Addr addr)
    { return process->validInstAddr(addr); }

    bool validDataAddr(Addr addr)
    { return process->validDataAddr(addr); }

    int getInstAsid() { return asid; }
    int getDataAsid() { return asid; }

    Fault dummyTranslation(MemReqPtr req)
    {
#if 0
        assert((req->vaddr >> 48 & 0xffff) == 0);
#endif

        // put the asid in the upper 16 bits of the paddr
        req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
        req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
        return No_Fault;
    }
    Fault translateInstReq(MemReqPtr req)
    {
        return dummyTranslation(req);
    }
    Fault translateDataReadReq(MemReqPtr req)
    {
        return dummyTranslation(req);
    }
    Fault translateDataWriteReq(MemReqPtr req)
    {
        return dummyTranslation(req);
    }

#endif

    template <class T>
    Fault read(MemReqPtr req, T& data)
    {
#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)
        if (req->flags & LOCKED) {
            MiscRegFile *cregs = &req->xc->regs.miscRegs;
            cregs->lock_addr = req->paddr;
            cregs->lock_flag = true;
        }
#endif
        return mem->read(req, data);
    }

    template <class T>
    Fault write(MemReqPtr req, T& data)
    {
#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)

        MiscRegFile *cregs;

        // If this is a store conditional, act appropriately
        if (req->flags & LOCKED) {
            cregs = &req->xc->regs.miscRegs;

            if (req->flags & UNCACHEABLE) {
                // Don't update result register (see stq_c in isa_desc)
                req->result = 2;
                req->xc->storeCondFailures = 0;//Needed? [RGD]
            } else {
                req->result = cregs->lock_flag;
                if (!cregs->lock_flag ||
                    ((cregs->lock_addr & ~0xf) != (req->paddr & ~0xf))) {
                    cregs->lock_flag = false;
                    if (((++req->xc->storeCondFailures) % 100000) == 0) {
                        std::cerr << "Warning: "
                                  << req->xc->storeCondFailures
                                  << " consecutive store conditional failures "
                                  << "on cpu " << req->xc->cpu_id
                                  << std::endl;
                    }
                    return No_Fault;
                }
                else req->xc->storeCondFailures = 0;
            }
        }

        // Need to clear any locked flags on other proccessors for
        // this address.  Only do this for succsful Store Conditionals
        // and all other stores (WH64?).  Unsuccessful Store
        // Conditionals would have returned above, and wouldn't fall
        // through.
        for (int i = 0; i < system->execContexts.size(); i++){
            cregs = &system->execContexts[i]->regs.miscRegs;
            if ((cregs->lock_addr & ~0xf) == (req->paddr & ~0xf)) {
                cregs->lock_flag = false;
            }
        }

#endif
        return mem->write(req, data);
    }

    virtual bool misspeculating();

    //
    // New accessors for new decoder.
    //
    uint64_t readIntReg(int reg_idx)
    {
        return regs.intRegFile[reg_idx];
    }

    float readFloatRegSingle(int reg_idx)
    {
        return (float)regs.floatRegFile.d[reg_idx];
    }

    double readFloatRegDouble(int reg_idx)
    {
        return regs.floatRegFile.d[reg_idx];
    }

    uint64_t readFloatRegInt(int reg_idx)
    {
        return regs.floatRegFile.q[reg_idx];
    }

    void setIntReg(int reg_idx, uint64_t val)
    {
        regs.intRegFile[reg_idx] = val;
    }

    void setFloatRegSingle(int reg_idx, float val)
    {
        regs.floatRegFile.d[reg_idx] = (double)val;
    }

    void setFloatRegDouble(int reg_idx, double val)
    {
        regs.floatRegFile.d[reg_idx] = val;
    }

    void setFloatRegInt(int reg_idx, uint64_t val)
    {
        regs.floatRegFile.q[reg_idx] = val;
    }

    uint64_t readPC()
    {
        return regs.pc;
    }

    void setNextPC(uint64_t val)
    {
        regs.npc = val;
    }

    uint64_t readUniq()
    {
        return regs.miscRegs.uniq;
    }

    void setUniq(uint64_t val)
    {
        regs.miscRegs.uniq = val;
    }

    uint64_t readFpcr()
    {
        return regs.miscRegs.fpcr;
    }

    void setFpcr(uint64_t val)
    {
        regs.miscRegs.fpcr = val;
    }

#ifdef FULL_SYSTEM
    uint64_t readIpr(int idx, Fault &fault);
    Fault setIpr(int idx, uint64_t val);
    Fault hwrei();
    void ev5_trap(Fault fault);
    bool simPalCheck(int palFunc);
#endif

#ifndef FULL_SYSTEM
    void syscall()
    {
        process->syscall(this);
    }
#endif
};

// for non-speculative execution context, spec_mode is always false
inline bool
ExecContext::misspeculating()
{
    return false;
}

#endif // __EXEC_CONTEXT_HH__
<|endoftext|>