<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/jingle_glue/ssl_socket_adapter.h"

#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "net/base/address_list.h"
#include "net/base/cert_verifier.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_errors.h"
#include "net/base/ssl_config_service.h"
#include "net/base/sys_addrinfo.h"
#include "net/socket/client_socket_factory.h"
#include "net/url_request/url_request_context.h"
#include "remoting/jingle_glue/utils.h"

namespace remoting {

SSLSocketAdapter* SSLSocketAdapter::Create(AsyncSocket* socket) {
  return new SSLSocketAdapter(socket);
}

SSLSocketAdapter::SSLSocketAdapter(AsyncSocket* socket)
    : SSLAdapter(socket),
      ignore_bad_cert_(false),
      cert_verifier_(new net::CertVerifier()),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          connected_callback_(this, &SSLSocketAdapter::OnConnected)),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          read_callback_(this, &SSLSocketAdapter::OnRead)),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          write_callback_(this, &SSLSocketAdapter::OnWrite)),
      ssl_state_(SSLSTATE_NONE),
      read_state_(IOSTATE_NONE),
      write_state_(IOSTATE_NONE) {
  transport_socket_ = new TransportSocket(socket, this);
}

SSLSocketAdapter::~SSLSocketAdapter() {
}

int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) {
  DCHECK(!restartable);
  hostname_ = hostname;

  if (socket_->GetState() != Socket::CS_CONNECTED) {
    ssl_state_ = SSLSTATE_WAIT;
    return 0;
  } else {
    return BeginSSL();
  }
}

int SSLSocketAdapter::BeginSSL() {
  if (!MessageLoop::current()) {
    // Certificate verification is done via the Chrome message loop.
    // Without this check, if we don't have a chrome message loop the
    // SSL connection just hangs silently.
    LOG(DFATAL) << "Chrome message loop (needed by SSL certificate "
                << "verification) does not exist";
    return net::ERR_UNEXPECTED;
  }

  // SSLConfigService is not thread-safe, and the default values for SSLConfig
  // are correct for us, so we don't use the config service to initialize this
  // object.
  net::SSLConfig ssl_config;
  transport_socket_->set_addr(talk_base::SocketAddress(hostname_, 0));
  ssl_socket_.reset(
      net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
          transport_socket_, net::HostPortPair(hostname_, 443), ssl_config,
          NULL /* ssl_host_info */,
          cert_verifier_.get()));

  int result = ssl_socket_->Connect(&connected_callback_);

  if (result == net::ERR_IO_PENDING || result == net::OK) {
    return 0;
  } else {
    LOG(ERROR) << "Could not start SSL: " << net::ErrorToString(result);
    return result;
  }
}

int SSLSocketAdapter::Send(const void* buf, size_t len) {
  if (ssl_state_ != SSLSTATE_CONNECTED) {
    return AsyncSocketAdapter::Send(buf, len);
  } else {
    scoped_refptr<net::IOBuffer> transport_buf(new net::IOBuffer(len));
    memcpy(transport_buf->data(), buf, len);

    int result = ssl_socket_->Write(transport_buf, len, NULL);
    if (result == net::ERR_IO_PENDING) {
      SetError(EWOULDBLOCK);
    }
    transport_buf = NULL;
    return result;
  }
}

int SSLSocketAdapter::Recv(void* buf, size_t len) {
  switch (ssl_state_) {
    case SSLSTATE_NONE:
      return AsyncSocketAdapter::Recv(buf, len);

    case SSLSTATE_WAIT:
      SetError(EWOULDBLOCK);
      return -1;

    case SSLSTATE_CONNECTED:
      switch (read_state_) {
        case IOSTATE_NONE: {
          transport_buf_ = new net::IOBuffer(len);
          int result = ssl_socket_->Read(transport_buf_, len, &read_callback_);
          if (result >= 0) {
            memcpy(buf, transport_buf_->data(), len);
          }

          if (result == net::ERR_IO_PENDING) {
            read_state_ = IOSTATE_PENDING;
            SetError(EWOULDBLOCK);
          } else {
            if (result < 0) {
              SetError(result);
              VLOG(1) << "Socket error " << result;
            }
            transport_buf_ = NULL;
          }
          return result;
        }
        case IOSTATE_PENDING:
          SetError(EWOULDBLOCK);
          return -1;

        case IOSTATE_COMPLETE:
          memcpy(buf, transport_buf_->data(), len);
          transport_buf_ = NULL;
          read_state_ = IOSTATE_NONE;
          return data_transferred_;
      }
  }

  NOTREACHED();
  return -1;
}

void SSLSocketAdapter::OnConnected(int result) {
  if (result == net::OK) {
    ssl_state_ = SSLSTATE_CONNECTED;
    OnConnectEvent(this);
  } else {
    LOG(WARNING) << "OnConnected failed with error " << result;
  }
}

void SSLSocketAdapter::OnRead(int result) {
  DCHECK(read_state_ == IOSTATE_PENDING);
  read_state_ = IOSTATE_COMPLETE;
  data_transferred_ = result;
  AsyncSocketAdapter::OnReadEvent(this);
}

void SSLSocketAdapter::OnWrite(int result) {
  DCHECK(write_state_ == IOSTATE_PENDING);
  write_state_ = IOSTATE_COMPLETE;
  data_transferred_ = result;
  AsyncSocketAdapter::OnWriteEvent(this);
}

void SSLSocketAdapter::OnConnectEvent(talk_base::AsyncSocket* socket) {
  if (ssl_state_ != SSLSTATE_WAIT) {
    AsyncSocketAdapter::OnConnectEvent(socket);
  } else {
    ssl_state_ = SSLSTATE_NONE;
    int result = BeginSSL();
    if (0 != result) {
      // TODO(zork): Handle this case gracefully.
      LOG(WARNING) << "BeginSSL() failed with " << result;
    }
  }
}

TransportSocket::TransportSocket(talk_base::AsyncSocket* socket,
                                 SSLSocketAdapter *ssl_adapter)
    : read_callback_(NULL),
      write_callback_(NULL),
      read_buffer_len_(0),
      write_buffer_len_(0),
      socket_(socket),
      was_used_to_convey_data_(false) {
  socket_->SignalReadEvent.connect(this, &TransportSocket::OnReadEvent);
  socket_->SignalWriteEvent.connect(this, &TransportSocket::OnWriteEvent);
}

TransportSocket::~TransportSocket() {
}

int TransportSocket::Connect(net::CompletionCallback* callback) {
  // Connect is never called by SSLClientSocket, instead SSLSocketAdapter
  // calls Connect() on socket_ directly.
  NOTREACHED();
  return false;
}

void TransportSocket::Disconnect() {
  socket_->Close();
}

bool TransportSocket::IsConnected() const {
  return (socket_->GetState() == talk_base::Socket::CS_CONNECTED);
}

bool TransportSocket::IsConnectedAndIdle() const {
  // Not implemented.
  NOTREACHED();
  return false;
}

int TransportSocket::GetPeerAddress(net::AddressList* address) const {
  talk_base::SocketAddress socket_address = socket_->GetRemoteAddress();

  // libjingle supports only IPv4 addresses.
  sockaddr_in ipv4addr;
  socket_address.ToSockAddr(&ipv4addr);

  struct addrinfo ai;
  memset(&ai, 0, sizeof(ai));
  ai.ai_family = ipv4addr.sin_family;
  ai.ai_socktype = SOCK_STREAM;
  ai.ai_protocol = IPPROTO_TCP;
  ai.ai_addr = reinterpret_cast<struct sockaddr*>(&ipv4addr);
  ai.ai_addrlen = sizeof(ipv4addr);

  address->Copy(&ai, false);
  return net::OK;
}

const net::BoundNetLog& TransportSocket::NetLog() const {
  return net_log_;
}

void TransportSocket::SetSubresourceSpeculation() {
  NOTREACHED();
}

void TransportSocket::SetOmniboxSpeculation() {
  NOTREACHED();
}

bool TransportSocket::WasEverUsed() const {
  // We don't use this in ClientSocketPools, so this should never be used.
  NOTREACHED();
  return was_used_to_convey_data_;
}

bool TransportSocket::UsingTCPFastOpen() const {
  return false;
}

int TransportSocket::Read(net::IOBuffer* buf, int buf_len,
                          net::CompletionCallback* callback) {
  DCHECK(buf);
  DCHECK(!read_callback_);
  DCHECK(!read_buffer_.get());
  int result = socket_->Recv(buf->data(), buf_len);
  if (result < 0) {
    result = MapPosixToChromeError(socket_->GetError());
    if (result == net::ERR_IO_PENDING) {
      read_callback_ = callback;
      read_buffer_ = buf;
      read_buffer_len_ = buf_len;
    }
  }
  if (result != net::ERR_IO_PENDING)
    was_used_to_convey_data_ = true;
  return result;
}

int TransportSocket::Write(net::IOBuffer* buf, int buf_len,
                           net::CompletionCallback* callback) {
  DCHECK(buf);
  DCHECK(!write_callback_);
  DCHECK(!write_buffer_.get());
  int result = socket_->Send(buf->data(), buf_len);
  if (result < 0) {
    result = MapPosixToChromeError(socket_->GetError());
    if (result == net::ERR_IO_PENDING) {
      write_callback_ = callback;
      write_buffer_ = buf;
      write_buffer_len_ = buf_len;
    }
  }
  if (result != net::ERR_IO_PENDING)
    was_used_to_convey_data_ = true;
  return result;
}

bool TransportSocket::SetReceiveBufferSize(int32 size) {
  // Not implemented.
  return false;
}

bool TransportSocket::SetSendBufferSize(int32 size) {
  // Not implemented.
  return false;
}

void TransportSocket::OnReadEvent(talk_base::AsyncSocket* socket) {
  if (read_callback_) {
    DCHECK(read_buffer_.get());
    net::CompletionCallback* callback = read_callback_;
    scoped_refptr<net::IOBuffer> buffer = read_buffer_;
    int buffer_len = read_buffer_len_;

    read_callback_ = NULL;
    read_buffer_ = NULL;
    read_buffer_len_ = 0;

    int result = socket_->Recv(buffer->data(), buffer_len);
    if (result < 0) {
      result = MapPosixToChromeError(socket_->GetError());
      if (result == net::ERR_IO_PENDING) {
        read_callback_ = callback;
        read_buffer_ = buffer;
        read_buffer_len_ = buffer_len;
        return;
      }
    }
    was_used_to_convey_data_ = true;
    callback->RunWithParams(Tuple1<int>(result));
  }
}

void TransportSocket::OnWriteEvent(talk_base::AsyncSocket* socket) {
  if (write_callback_) {
    DCHECK(write_buffer_.get());
    net::CompletionCallback* callback = write_callback_;
    scoped_refptr<net::IOBuffer> buffer = write_buffer_;
    int buffer_len = write_buffer_len_;

    write_callback_ = NULL;
    write_buffer_ = NULL;
    write_buffer_len_ = 0;

    int result = socket_->Send(buffer->data(), buffer_len);
    if (result < 0) {
      result = MapPosixToChromeError(socket_->GetError());
      if (result == net::ERR_IO_PENDING) {
        write_callback_ = callback;
        write_buffer_ = buffer;
        write_buffer_len_ = buffer_len;
        return;
      }
    }
    was_used_to_convey_data_ = true;
    callback->RunWithParams(Tuple1<int>(result));
  }
}

}  // namespace remoting
<commit_msg>Hardcode gmail cert for chromoting.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/jingle_glue/ssl_socket_adapter.h"

#include "base/base64.h"
#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "net/base/address_list.h"
#include "net/base/cert_verifier.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_errors.h"
#include "net/base/ssl_config_service.h"
#include "net/base/sys_addrinfo.h"
#include "net/socket/client_socket_factory.h"
#include "net/url_request/url_request_context.h"
#include "remoting/jingle_glue/utils.h"

namespace remoting {

namespace {

// NSS doesn't load root certificates when running in sandbox, so we
// need to have gmail's cert hardcoded.
//
// TODO(sergeyu): Remove this when we don't make XMPP connection from
// inside of sandbox.
const char kGmailCertBase64[] =
    "MIIC2TCCAkKgAwIBAgIDBz+SMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT"
    "MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0"
    "aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcwNDExMTcxNzM4WhcNMTIwNDEwMTcxNzM4"
    "WjBkMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN"
    "TW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEjAQBgNVBAMTCWdt"
    "YWlsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1Hds2jWwXAVGef06"
    "7PeSJF/h9BnoYlTdykx0lBTDc92/JLvuq0lJkytqll1UR4kHmF4vwqQkwcqOK03w"
    "k8qDK8fh6M13PYhvPEXP02ozsuL3vqE8hcCva2B9HVnOPY17Qok37rYQ+yexswN5"
    "eh0+93nddEa1PyHgEQ8CDKCJaWUCAwEAAaOBrjCBqzAOBgNVHQ8BAf8EBAMCBPAw"
    "HQYDVR0OBBYEFJcjzXEevMEDIEvuQiT7puEJY737MDoGA1UdHwQzMDEwL6AtoCuG"
    "KWh0dHA6Ly9jcmwuZ2VvdHJ1c3QuY29tL2NybHMvc2VjdXJlY2EuY3JsMB8GA1Ud"
    "IwQYMBaAFEjmaPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdJQQWMBQGCCsGAQUFBwMB"
    "BggrBgEFBQcDAjANBgkqhkiG9w0BAQUFAAOBgQB74cGpjdENf9U+WEd29dfzY3Tz"
    "JehnlY5cH5as8bOTe7PNPzj967OJ7TPWEycMwlS7CsqIsmfRGOFFfoHxo+iPugZ8"
    "uO2Kd++QHCXL+MumGjkW4FcTFmceV/Q12Wdh3WApcqIZZciQ79MAeFh7bzteAYqf"
    "wC98YQwylC9wVhf1yw==";

}  // namespace

SSLSocketAdapter* SSLSocketAdapter::Create(AsyncSocket* socket) {
  return new SSLSocketAdapter(socket);
}

SSLSocketAdapter::SSLSocketAdapter(AsyncSocket* socket)
    : SSLAdapter(socket),
      ignore_bad_cert_(false),
      cert_verifier_(new net::CertVerifier()),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          connected_callback_(this, &SSLSocketAdapter::OnConnected)),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          read_callback_(this, &SSLSocketAdapter::OnRead)),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          write_callback_(this, &SSLSocketAdapter::OnWrite)),
      ssl_state_(SSLSTATE_NONE),
      read_state_(IOSTATE_NONE),
      write_state_(IOSTATE_NONE) {
  transport_socket_ = new TransportSocket(socket, this);
}

SSLSocketAdapter::~SSLSocketAdapter() {
}

int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) {
  DCHECK(!restartable);
  hostname_ = hostname;

  if (socket_->GetState() != Socket::CS_CONNECTED) {
    ssl_state_ = SSLSTATE_WAIT;
    return 0;
  } else {
    return BeginSSL();
  }
}

int SSLSocketAdapter::BeginSSL() {
  if (!MessageLoop::current()) {
    // Certificate verification is done via the Chrome message loop.
    // Without this check, if we don't have a chrome message loop the
    // SSL connection just hangs silently.
    LOG(DFATAL) << "Chrome message loop (needed by SSL certificate "
                << "verification) does not exist";
    return net::ERR_UNEXPECTED;
  }

  // SSLConfigService is not thread-safe, and the default values for SSLConfig
  // are correct for us, so we don't use the config service to initialize this
  // object.
  net::SSLConfig ssl_config;

  std::string gmail_cert_binary;
  base::Base64Decode(kGmailCertBase64, &gmail_cert_binary);
  scoped_refptr<net::X509Certificate> gmail_cert =
      net::X509Certificate::CreateFromBytes(gmail_cert_binary.data(),
                                            gmail_cert_binary.size());
  DCHECK(gmail_cert);
  net::SSLConfig::CertAndStatus gmail_cert_status;
  gmail_cert_status.cert = gmail_cert;
  gmail_cert_status.cert_status = 0;
  ssl_config.allowed_bad_certs.push_back(gmail_cert_status);

  transport_socket_->set_addr(talk_base::SocketAddress(hostname_, 0));
  ssl_socket_.reset(
      net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
          transport_socket_, net::HostPortPair(hostname_, 443), ssl_config,
          NULL /* ssl_host_info */,
          cert_verifier_.get()));

  int result = ssl_socket_->Connect(&connected_callback_);

  if (result == net::ERR_IO_PENDING || result == net::OK) {
    return 0;
  } else {
    LOG(ERROR) << "Could not start SSL: " << net::ErrorToString(result);
    return result;
  }
}

int SSLSocketAdapter::Send(const void* buf, size_t len) {
  if (ssl_state_ != SSLSTATE_CONNECTED) {
    return AsyncSocketAdapter::Send(buf, len);
  } else {
    scoped_refptr<net::IOBuffer> transport_buf(new net::IOBuffer(len));
    memcpy(transport_buf->data(), buf, len);

    int result = ssl_socket_->Write(transport_buf, len, NULL);
    if (result == net::ERR_IO_PENDING) {
      SetError(EWOULDBLOCK);
    }
    transport_buf = NULL;
    return result;
  }
}

int SSLSocketAdapter::Recv(void* buf, size_t len) {
  switch (ssl_state_) {
    case SSLSTATE_NONE:
      return AsyncSocketAdapter::Recv(buf, len);

    case SSLSTATE_WAIT:
      SetError(EWOULDBLOCK);
      return -1;

    case SSLSTATE_CONNECTED:
      switch (read_state_) {
        case IOSTATE_NONE: {
          transport_buf_ = new net::IOBuffer(len);
          int result = ssl_socket_->Read(transport_buf_, len, &read_callback_);
          if (result >= 0) {
            memcpy(buf, transport_buf_->data(), len);
          }

          if (result == net::ERR_IO_PENDING) {
            read_state_ = IOSTATE_PENDING;
            SetError(EWOULDBLOCK);
          } else {
            if (result < 0) {
              SetError(result);
              VLOG(1) << "Socket error " << result;
            }
            transport_buf_ = NULL;
          }
          return result;
        }
        case IOSTATE_PENDING:
          SetError(EWOULDBLOCK);
          return -1;

        case IOSTATE_COMPLETE:
          memcpy(buf, transport_buf_->data(), len);
          transport_buf_ = NULL;
          read_state_ = IOSTATE_NONE;
          return data_transferred_;
      }
  }

  NOTREACHED();
  return -1;
}

void SSLSocketAdapter::OnConnected(int result) {
  if (result == net::OK) {
    ssl_state_ = SSLSTATE_CONNECTED;
    OnConnectEvent(this);
  } else {
    LOG(WARNING) << "OnConnected failed with error " << result;
  }
}

void SSLSocketAdapter::OnRead(int result) {
  DCHECK(read_state_ == IOSTATE_PENDING);
  read_state_ = IOSTATE_COMPLETE;
  data_transferred_ = result;
  AsyncSocketAdapter::OnReadEvent(this);
}

void SSLSocketAdapter::OnWrite(int result) {
  DCHECK(write_state_ == IOSTATE_PENDING);
  write_state_ = IOSTATE_COMPLETE;
  data_transferred_ = result;
  AsyncSocketAdapter::OnWriteEvent(this);
}

void SSLSocketAdapter::OnConnectEvent(talk_base::AsyncSocket* socket) {
  if (ssl_state_ != SSLSTATE_WAIT) {
    AsyncSocketAdapter::OnConnectEvent(socket);
  } else {
    ssl_state_ = SSLSTATE_NONE;
    int result = BeginSSL();
    if (0 != result) {
      // TODO(zork): Handle this case gracefully.
      LOG(WARNING) << "BeginSSL() failed with " << result;
    }
  }
}

TransportSocket::TransportSocket(talk_base::AsyncSocket* socket,
                                 SSLSocketAdapter *ssl_adapter)
    : read_callback_(NULL),
      write_callback_(NULL),
      read_buffer_len_(0),
      write_buffer_len_(0),
      socket_(socket),
      was_used_to_convey_data_(false) {
  socket_->SignalReadEvent.connect(this, &TransportSocket::OnReadEvent);
  socket_->SignalWriteEvent.connect(this, &TransportSocket::OnWriteEvent);
}

TransportSocket::~TransportSocket() {
}

int TransportSocket::Connect(net::CompletionCallback* callback) {
  // Connect is never called by SSLClientSocket, instead SSLSocketAdapter
  // calls Connect() on socket_ directly.
  NOTREACHED();
  return false;
}

void TransportSocket::Disconnect() {
  socket_->Close();
}

bool TransportSocket::IsConnected() const {
  return (socket_->GetState() == talk_base::Socket::CS_CONNECTED);
}

bool TransportSocket::IsConnectedAndIdle() const {
  // Not implemented.
  NOTREACHED();
  return false;
}

int TransportSocket::GetPeerAddress(net::AddressList* address) const {
  talk_base::SocketAddress socket_address = socket_->GetRemoteAddress();

  // libjingle supports only IPv4 addresses.
  sockaddr_in ipv4addr;
  socket_address.ToSockAddr(&ipv4addr);

  struct addrinfo ai;
  memset(&ai, 0, sizeof(ai));
  ai.ai_family = ipv4addr.sin_family;
  ai.ai_socktype = SOCK_STREAM;
  ai.ai_protocol = IPPROTO_TCP;
  ai.ai_addr = reinterpret_cast<struct sockaddr*>(&ipv4addr);
  ai.ai_addrlen = sizeof(ipv4addr);

  address->Copy(&ai, false);
  return net::OK;
}

const net::BoundNetLog& TransportSocket::NetLog() const {
  return net_log_;
}

void TransportSocket::SetSubresourceSpeculation() {
  NOTREACHED();
}

void TransportSocket::SetOmniboxSpeculation() {
  NOTREACHED();
}

bool TransportSocket::WasEverUsed() const {
  // We don't use this in ClientSocketPools, so this should never be used.
  NOTREACHED();
  return was_used_to_convey_data_;
}

bool TransportSocket::UsingTCPFastOpen() const {
  return false;
}

int TransportSocket::Read(net::IOBuffer* buf, int buf_len,
                          net::CompletionCallback* callback) {
  DCHECK(buf);
  DCHECK(!read_callback_);
  DCHECK(!read_buffer_.get());
  int result = socket_->Recv(buf->data(), buf_len);
  if (result < 0) {
    result = MapPosixToChromeError(socket_->GetError());
    if (result == net::ERR_IO_PENDING) {
      read_callback_ = callback;
      read_buffer_ = buf;
      read_buffer_len_ = buf_len;
    }
  }
  if (result != net::ERR_IO_PENDING)
    was_used_to_convey_data_ = true;
  return result;
}

int TransportSocket::Write(net::IOBuffer* buf, int buf_len,
                           net::CompletionCallback* callback) {
  DCHECK(buf);
  DCHECK(!write_callback_);
  DCHECK(!write_buffer_.get());
  int result = socket_->Send(buf->data(), buf_len);
  if (result < 0) {
    result = MapPosixToChromeError(socket_->GetError());
    if (result == net::ERR_IO_PENDING) {
      write_callback_ = callback;
      write_buffer_ = buf;
      write_buffer_len_ = buf_len;
    }
  }
  if (result != net::ERR_IO_PENDING)
    was_used_to_convey_data_ = true;
  return result;
}

bool TransportSocket::SetReceiveBufferSize(int32 size) {
  // Not implemented.
  return false;
}

bool TransportSocket::SetSendBufferSize(int32 size) {
  // Not implemented.
  return false;
}

void TransportSocket::OnReadEvent(talk_base::AsyncSocket* socket) {
  if (read_callback_) {
    DCHECK(read_buffer_.get());
    net::CompletionCallback* callback = read_callback_;
    scoped_refptr<net::IOBuffer> buffer = read_buffer_;
    int buffer_len = read_buffer_len_;

    read_callback_ = NULL;
    read_buffer_ = NULL;
    read_buffer_len_ = 0;

    int result = socket_->Recv(buffer->data(), buffer_len);
    if (result < 0) {
      result = MapPosixToChromeError(socket_->GetError());
      if (result == net::ERR_IO_PENDING) {
        read_callback_ = callback;
        read_buffer_ = buffer;
        read_buffer_len_ = buffer_len;
        return;
      }
    }
    was_used_to_convey_data_ = true;
    callback->RunWithParams(Tuple1<int>(result));
  }
}

void TransportSocket::OnWriteEvent(talk_base::AsyncSocket* socket) {
  if (write_callback_) {
    DCHECK(write_buffer_.get());
    net::CompletionCallback* callback = write_callback_;
    scoped_refptr<net::IOBuffer> buffer = write_buffer_;
    int buffer_len = write_buffer_len_;

    write_callback_ = NULL;
    write_buffer_ = NULL;
    write_buffer_len_ = 0;

    int result = socket_->Send(buffer->data(), buffer_len);
    if (result < 0) {
      result = MapPosixToChromeError(socket_->GetError());
      if (result == net::ERR_IO_PENDING) {
        write_callback_ = callback;
        write_buffer_ = buffer;
        write_buffer_len_ = buffer_len;
        return;
      }
    }
    was_used_to_convey_data_ = true;
    callback->RunWithParams(Tuple1<int>(result));
  }
}

}  // namespace remoting
<|endoftext|>


<commit_before>// @(#)root/rint:$Name:  $:$Id: TRint.cxx,v 1.35 2004/06/03 05:11:00 brun Exp $
// Author: Rene Brun   17/02/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Rint                                                                 //
//                                                                      //
// Rint is the ROOT Interactive Interface. It allows interactive access //
// to the ROOT system via the CINT C/C++ interpreter.                   //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TClass.h"
#include "TVirtualX.h"
#include "Getline.h"
#include "TStyle.h"
#include "TObjectTable.h"
#include "TClassTable.h"
#include "TStopwatch.h"
#include "TBenchmark.h"
#include "TRint.h"
#include "TSystem.h"
#include "TEnv.h"
#include "TSysEvtHandler.h"
#include "TError.h"
#include "TException.h"
#include "TInterpreter.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TFile.h"
#include "TMapFile.h"
#include "TTabCom.h"
#include "TError.h"

#ifdef R__UNIX
#include <signal.h>

extern "C" {
   extern int G__get_security_error();
   extern int G__genericerror(const char* msg);
}
#endif

static Int_t key_pressed(Int_t key) { gApplication->KeyPressed(key); return 0; }

//----- Interrupt signal handler -----------------------------------------------
//______________________________________________________________________________
class TInterruptHandler : public TSignalHandler {
public:
   TInterruptHandler() : TSignalHandler(kSigInterrupt, kFALSE) { }
   Bool_t  Notify();
};

//______________________________________________________________________________
Bool_t TInterruptHandler::Notify()
{
   // TRint interrupt handler.

   if (fDelay) {
      fDelay++;
      return kTRUE;
   }

   // make sure we use the sbrk heap (in case of mapped files)
   gMmallocDesc = 0;

   if (!G__get_security_error())
      G__genericerror("\n *** Break *** keyboard interrupt");
   else {
      Break("TInterruptHandler::Notify", "keyboard interrupt");
      if (TROOT::Initialized()) {
         Getlinem(kInit, "Root > ");
         gInterpreter->RewindDictionary();
         Throw(GetSignal());
      }
   }
   return kTRUE;
}

//----- Terminal Input file handler --------------------------------------------
//______________________________________________________________________________
class TTermInputHandler : public TFileHandler {
public:
   TTermInputHandler(Int_t fd) : TFileHandler(fd, 1) { }
   Bool_t Notify();
   Bool_t ReadNotify() { return Notify(); }
};

//______________________________________________________________________________
Bool_t TTermInputHandler::Notify()
{
   return gApplication->HandleTermInput();
}

ClassImp(TRint)

//______________________________________________________________________________
TRint::TRint(const char *appClassName, Int_t *argc, char **argv, void *options,
             Int_t numOptions, Bool_t noLogo)
       : TApplication(appClassName, argc, argv, options, numOptions)
{
   // Create an application environment. The TRint environment provides an
   // interface to the WM manager functionality and eventloop via inheritance
   // of TApplication and in addition provides interactive access to
   // the CINT C++ interpreter via the command line.

   fNcmd          = 0;
   fDefaultPrompt = "root [%d] ";
   fInterrupt     = kFALSE;

   gBenchmark = new TBenchmark();

   if (!noLogo && !NoLogoOpt())
      PrintLogo();

   // Everybody expects iostream to be available, so load it...
   ProcessLine("#include <iostream>", kTRUE);
   ProcessLine("#include <_string>", kTRUE); // for std::string iostream.

   // Allow the usage of ClassDef and ClassImp in interpreted macros
   ProcessLine("#include <RtypesCint.h>", kTRUE);

   // The following lib is also useful to have, make sure they are loaded...
   gROOT->LoadClass("THtml",  "Html");

   // Load user functions
   const char *logon;
   logon = gEnv->GetValue("Rint.Load", (char*)0);
   if (logon) {
      char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
      if (mac)
         ProcessLine(Form(".L %s",logon),kTRUE);
      delete [] mac;
   }

   // Execute logon macro
   logon = gEnv->GetValue("Rint.Logon", (char*)0);
   if (logon && !NoLogOpt()) {
      char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
      if (mac)
         ProcessFile(logon);
      delete [] mac;
   }

   gInterpreter->SaveContext();
   gInterpreter->SaveGlobalsContext();

   // Install interrupt and terminal input handlers
   TInterruptHandler *ih = new TInterruptHandler();
   ih->Add();
   SetSignalHandler(ih);

   // Handle stdin events
   fInputHandler = new TTermInputHandler(0);
   fInputHandler->Add();

   // Goto into raw terminal input mode
   char defhist[128];
#ifndef R__VMS
   sprintf(defhist, "%s/.root_hist", gSystem->Getenv("HOME"));
#else
   sprintf(defhist, "%s.root_hist", gSystem->Getenv("HOME"));
#endif
   logon = gEnv->GetValue("Rint.History", defhist);
   Gl_histinit((char *)logon);
   Gl_windowchanged();

   // Setup for tab completion
   gTabCom = new TTabCom;
   Gl_in_key = &key_pressed;
}

//______________________________________________________________________________
TRint::~TRint()
{

}

//______________________________________________________________________________
void TRint::Run(Bool_t retrn)
{
   // Main application eventloop. First process files given on the command
   // line and then go into the main application event loop, unless the -q
   // command line option was specfied in which case the program terminates.
   // When retrun is true this method returns even when -q was specified.
   //
   // When QuitOpt is true and retrn is false, terminate the application with
   // an error code equal to either the ProcessLine error (if any) or the
   // return value of the command casted to a long.

   Getlinem(kInit, GetPrompt());

   Long_t retval = 0;
   Int_t  error = 0;

   // Process shell command line input files
   if (InputFiles()) {
      Bool_t needGetlinemInit = kFALSE;
      TIter next(InputFiles());
      RETRY {
         retval = 0; error = 0;
         Int_t nfile = 0;
         TObjString *file;
         while ((file = (TObjString *)next())) {
            char cmd[256];
            if (!fNcmd)
               printf("\n");
            if (file->String().EndsWith(".root")) {
               const char *rfile = (const char*)file->String();
               Printf("Attaching file %s as _file%d...", rfile, nfile);
               sprintf(cmd, "TFile *_file%d = TFile::Open(\"%s\")", nfile++, rfile);
            } else {
               Printf("Processing %s...", (const char*)file->String());
               sprintf(cmd, ".x %s", (const char*)file->String());
            }
            Getlinem(kCleanUp, 0);
            Gl_histadd(cmd);
            fNcmd++;

            // The ProcessLine might throw an 'exception'.  In this case,
            // GetLinem(kInit,"Root >") is called and we are jump back
            // to RETRY ... and we have to avoid the Getlinem(kInit, GetPrompt());
            needGetlinemInit = kFALSE;
            retval = ProcessLine(cmd, kFALSE, &error);

            // The ProcessLine has successfully completed and we need
            // to call Getlinem(kInit, GetPrompt());
            needGetlinemInit = kTRUE;

            if (error != 0) break;
         }
      } ENDTRY;

      if (QuitOpt()) {
         if (retrn) return;
         Terminate(error == 0 ? retval : error);
      }

      ClearInputFiles();

      if (needGetlinemInit) Getlinem(kInit, GetPrompt());
   }

   if (QuitOpt()) {
      printf("\n");
      if (retrn) return;
      Terminate(0);
   }

   TApplication::Run(retrn);

   Getlinem(kCleanUp, 0);
}

//______________________________________________________________________________
void TRint::PrintLogo()
{
   // Print the ROOT logo on standard output.

   Int_t iday,imonth,iyear;
   static const char *months[] = {"January","February","March","April","May",
                                  "June","July","August","September","October",
                                  "November","December"};
   const char *root_version = gROOT->GetVersion();
   Int_t idatqq = gROOT->GetVersionDate();
   iday   = idatqq%100;
   imonth = (idatqq/100)%100;
   iyear  = (idatqq/10000);
   char *root_date = Form("%d %s %4d",iday,months[imonth-1],iyear);

   Printf("  *******************************************");
   Printf("  *                                         *");
   Printf("  *        W E L C O M E  to  R O O T       *");
   Printf("  *                                         *");
   Printf("  *   Version%10s %17s   *", root_version, root_date);
// Printf("  *            Development version          *");
   Printf("  *                                         *");
   Printf("  *  You are welcome to visit our Web site  *");
   Printf("  *          http://root.cern.ch            *");
   Printf("  *                                         *");
   Printf("  *******************************************");

   if (strstr(gVirtualX->GetName(), "TTF")) {
      Int_t major, minor, patch;
      //TTF::Version(major, minor, patch);
      // avoid dependency on libGraf and hard code, will not change too often
      major = 2; minor = 1; patch = 3;
      Printf("\nFreeType Engine v%d.%d.%d used to render TrueType fonts.",
             major, minor, patch);
   }
#ifdef _REENTRANT
   else
      printf("\n");
   Printf("Compiled for %s with thread support.", gSystem->GetBuildArch());
#else
   else
      printf("\n");
   Printf("Compiled for %s.", gSystem->GetBuildArch());
#endif

   gInterpreter->PrintIntro();

#ifdef R__UNIX
   // Popdown X logo, only if started with -splash option
   for (int i = 0; i < Argc(); i++)
      if (!strcmp(Argv(i), "-splash"))
         kill(getppid(), SIGUSR1);
#endif
}

//______________________________________________________________________________
char *TRint::GetPrompt()
{
   // Get prompt from interpreter. Either "root [n]" or "end with '}'".

   char *s = gInterpreter->GetPrompt();
   if (s[0])
      strcpy(fPrompt, s);
   else
      sprintf(fPrompt, fDefaultPrompt.Data(), fNcmd);

   return fPrompt;
}

//______________________________________________________________________________
const char *TRint::SetPrompt(const char *newPrompt)
{
   // Set a new default prompt. It returns the previous prompt.
   // The prompt may contain a %d which will be replaced by the commend
   // number. The default prompt is "root [%d] ". The maximum length of
   // the prompt is 55 characters. To set the prompt in an interactive
   // session do:
   // root [0] ((TRint*)gROOT->GetApplication())->SetPrompt("aap> ")
   // aap>

   static TString op = fDefaultPrompt;

   if (newPrompt && strlen(newPrompt) <= 55)
      fDefaultPrompt = newPrompt;
   else
      Error("SetPrompt", "newPrompt too long (> 55 characters)");

   return op.Data();
}

//______________________________________________________________________________
Bool_t TRint::HandleTermInput()
{
   // Handle input coming from terminal.

   static TStopwatch timer;
   char *line;

   if ((line = Getlinem(kOneChar, 0))) {
      if (line[0] == 0 && Gl_eof())
         Terminate(0);

      gVirtualX->SetKeyAutoRepeat(kTRUE);

      Gl_histadd(line);

      TString sline = line;
      line[0] = 0;

      // strip off '\n' and leading and trailing blanks
      sline = sline.Chop();
      sline = sline.Strip(TString::kBoth);
      ReturnPressed((char*)sline.Data());

      fInterrupt = kFALSE;

      if (!gInterpreter->GetMore() && !sline.IsNull()) fNcmd++;

      // prevent recursive calling of this input handler
      fInputHandler->DeActivate();

      if (gROOT->Timer()) timer.Start();

      Bool_t added = kFALSE;
#ifdef R__EH
      try {
#endif
         TRY {
            ProcessLine(sline);
         } CATCH(excode) {
            // enable again input handler
            fInputHandler->Activate();
            added = kTRUE;
            Throw(excode);
         } ENDTRY;
#ifdef R__EH
      }
      // handle every exception
      catch (...) {
         // enable again intput handler
         if (!added) fInputHandler->Activate();
         throw;
      }
#endif

      if (gROOT->Timer()) timer.Print("u");

      // enable again intput handler
      fInputHandler->Activate();

      if (!sline.BeginsWith(".reset"))
         gInterpreter->EndOfLineAction();

      gTabCom->ClearAll();
      Getlinem(kInit, GetPrompt());
   }
   return kTRUE;
}

//______________________________________________________________________________
void TRint::Terminate(Int_t status)
{
   // Terminate the application. Reset the terminal to sane mode and call
   // the logoff macro defined via Rint.Logoff environment variable.

   Getlinem(kCleanUp, 0);

   if (ReturnFromRun()) {
      gSystem->ExitLoop();
   } else {
      //Execute logoff macro
      const char *logoff;
      logoff = gEnv->GetValue("Rint.Logoff", (char*)0);
      if (logoff && !NoLogOpt()) {
         char *mac = gSystem->Which(TROOT::GetMacroPath(), logoff, kReadPermission);
         if (mac)
            ProcessFile(logoff);
         delete [] mac;
      }

      gSystem->Exit(status);
   }
}

//______________________________________________________________________________
void TRint::SetEchoMode(Bool_t mode)
{
   // Set console mode:
   //
   //  mode = kTRUE  - echo input symbols
   //  mode = kFALSE - noecho input symbols

   Gl_config("noecho", mode ? 0 : 1);
}
<commit_msg>default loading of libPostscript was accidentally removed.<commit_after>// @(#)root/rint:$Name:  $:$Id: TRint.cxx,v 1.36 2004/06/13 16:26:36 rdm Exp $
// Author: Rene Brun   17/02/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Rint                                                                 //
//                                                                      //
// Rint is the ROOT Interactive Interface. It allows interactive access //
// to the ROOT system via the CINT C/C++ interpreter.                   //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TClass.h"
#include "TVirtualX.h"
#include "Getline.h"
#include "TStyle.h"
#include "TObjectTable.h"
#include "TClassTable.h"
#include "TStopwatch.h"
#include "TBenchmark.h"
#include "TRint.h"
#include "TSystem.h"
#include "TEnv.h"
#include "TSysEvtHandler.h"
#include "TError.h"
#include "TException.h"
#include "TInterpreter.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TFile.h"
#include "TMapFile.h"
#include "TTabCom.h"
#include "TError.h"

#ifdef R__UNIX
#include <signal.h>

extern "C" {
   extern int G__get_security_error();
   extern int G__genericerror(const char* msg);
}
#endif

static Int_t key_pressed(Int_t key) { gApplication->KeyPressed(key); return 0; }

//----- Interrupt signal handler -----------------------------------------------
//______________________________________________________________________________
class TInterruptHandler : public TSignalHandler {
public:
   TInterruptHandler() : TSignalHandler(kSigInterrupt, kFALSE) { }
   Bool_t  Notify();
};

//______________________________________________________________________________
Bool_t TInterruptHandler::Notify()
{
   // TRint interrupt handler.

   if (fDelay) {
      fDelay++;
      return kTRUE;
   }

   // make sure we use the sbrk heap (in case of mapped files)
   gMmallocDesc = 0;

   if (!G__get_security_error())
      G__genericerror("\n *** Break *** keyboard interrupt");
   else {
      Break("TInterruptHandler::Notify", "keyboard interrupt");
      if (TROOT::Initialized()) {
         Getlinem(kInit, "Root > ");
         gInterpreter->RewindDictionary();
         Throw(GetSignal());
      }
   }
   return kTRUE;
}

//----- Terminal Input file handler --------------------------------------------
//______________________________________________________________________________
class TTermInputHandler : public TFileHandler {
public:
   TTermInputHandler(Int_t fd) : TFileHandler(fd, 1) { }
   Bool_t Notify();
   Bool_t ReadNotify() { return Notify(); }
};

//______________________________________________________________________________
Bool_t TTermInputHandler::Notify()
{
   return gApplication->HandleTermInput();
}

ClassImp(TRint)

//______________________________________________________________________________
TRint::TRint(const char *appClassName, Int_t *argc, char **argv, void *options,
             Int_t numOptions, Bool_t noLogo)
       : TApplication(appClassName, argc, argv, options, numOptions)
{
   // Create an application environment. The TRint environment provides an
   // interface to the WM manager functionality and eventloop via inheritance
   // of TApplication and in addition provides interactive access to
   // the CINT C++ interpreter via the command line.

   fNcmd          = 0;
   fDefaultPrompt = "root [%d] ";
   fInterrupt     = kFALSE;

   gBenchmark = new TBenchmark();

   if (!noLogo && !NoLogoOpt())
      PrintLogo();

   // Everybody expects iostream to be available, so load it...
   ProcessLine("#include <iostream>", kTRUE);
   ProcessLine("#include <_string>", kTRUE); // for std::string iostream.

   // Allow the usage of ClassDef and ClassImp in interpreted macros
   ProcessLine("#include <RtypesCint.h>", kTRUE);

   // The following libs are also useful to have, make sure they are loaded...
   gROOT->LoadClass("TPostScript", "Postscript");
   gROOT->LoadClass("THtml",       "Html");

   // Load user functions
   const char *logon;
   logon = gEnv->GetValue("Rint.Load", (char*)0);
   if (logon) {
      char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
      if (mac)
         ProcessLine(Form(".L %s",logon),kTRUE);
      delete [] mac;
   }

   // Execute logon macro
   logon = gEnv->GetValue("Rint.Logon", (char*)0);
   if (logon && !NoLogOpt()) {
      char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
      if (mac)
         ProcessFile(logon);
      delete [] mac;
   }

   gInterpreter->SaveContext();
   gInterpreter->SaveGlobalsContext();

   // Install interrupt and terminal input handlers
   TInterruptHandler *ih = new TInterruptHandler();
   ih->Add();
   SetSignalHandler(ih);

   // Handle stdin events
   fInputHandler = new TTermInputHandler(0);
   fInputHandler->Add();

   // Goto into raw terminal input mode
   char defhist[128];
#ifndef R__VMS
   sprintf(defhist, "%s/.root_hist", gSystem->Getenv("HOME"));
#else
   sprintf(defhist, "%s.root_hist", gSystem->Getenv("HOME"));
#endif
   logon = gEnv->GetValue("Rint.History", defhist);
   Gl_histinit((char *)logon);
   Gl_windowchanged();

   // Setup for tab completion
   gTabCom = new TTabCom;
   Gl_in_key = &key_pressed;
}

//______________________________________________________________________________
TRint::~TRint()
{

}

//______________________________________________________________________________
void TRint::Run(Bool_t retrn)
{
   // Main application eventloop. First process files given on the command
   // line and then go into the main application event loop, unless the -q
   // command line option was specfied in which case the program terminates.
   // When retrun is true this method returns even when -q was specified.
   //
   // When QuitOpt is true and retrn is false, terminate the application with
   // an error code equal to either the ProcessLine error (if any) or the
   // return value of the command casted to a long.

   Getlinem(kInit, GetPrompt());

   Long_t retval = 0;
   Int_t  error = 0;

   // Process shell command line input files
   if (InputFiles()) {
      Bool_t needGetlinemInit = kFALSE;
      TIter next(InputFiles());
      RETRY {
         retval = 0; error = 0;
         Int_t nfile = 0;
         TObjString *file;
         while ((file = (TObjString *)next())) {
            char cmd[256];
            if (!fNcmd)
               printf("\n");
            if (file->String().EndsWith(".root")) {
               const char *rfile = (const char*)file->String();
               Printf("Attaching file %s as _file%d...", rfile, nfile);
               sprintf(cmd, "TFile *_file%d = TFile::Open(\"%s\")", nfile++, rfile);
            } else {
               Printf("Processing %s...", (const char*)file->String());
               sprintf(cmd, ".x %s", (const char*)file->String());
            }
            Getlinem(kCleanUp, 0);
            Gl_histadd(cmd);
            fNcmd++;

            // The ProcessLine might throw an 'exception'.  In this case,
            // GetLinem(kInit,"Root >") is called and we are jump back
            // to RETRY ... and we have to avoid the Getlinem(kInit, GetPrompt());
            needGetlinemInit = kFALSE;
            retval = ProcessLine(cmd, kFALSE, &error);

            // The ProcessLine has successfully completed and we need
            // to call Getlinem(kInit, GetPrompt());
            needGetlinemInit = kTRUE;

            if (error != 0) break;
         }
      } ENDTRY;

      if (QuitOpt()) {
         if (retrn) return;
         Terminate(error == 0 ? retval : error);
      }

      ClearInputFiles();

      if (needGetlinemInit) Getlinem(kInit, GetPrompt());
   }

   if (QuitOpt()) {
      printf("\n");
      if (retrn) return;
      Terminate(0);
   }

   TApplication::Run(retrn);

   Getlinem(kCleanUp, 0);
}

//______________________________________________________________________________
void TRint::PrintLogo()
{
   // Print the ROOT logo on standard output.

   Int_t iday,imonth,iyear;
   static const char *months[] = {"January","February","March","April","May",
                                  "June","July","August","September","October",
                                  "November","December"};
   const char *root_version = gROOT->GetVersion();
   Int_t idatqq = gROOT->GetVersionDate();
   iday   = idatqq%100;
   imonth = (idatqq/100)%100;
   iyear  = (idatqq/10000);
   char *root_date = Form("%d %s %4d",iday,months[imonth-1],iyear);

   Printf("  *******************************************");
   Printf("  *                                         *");
   Printf("  *        W E L C O M E  to  R O O T       *");
   Printf("  *                                         *");
   Printf("  *   Version%10s %17s   *", root_version, root_date);
// Printf("  *            Development version          *");
   Printf("  *                                         *");
   Printf("  *  You are welcome to visit our Web site  *");
   Printf("  *          http://root.cern.ch            *");
   Printf("  *                                         *");
   Printf("  *******************************************");

   if (strstr(gVirtualX->GetName(), "TTF")) {
      Int_t major, minor, patch;
      //TTF::Version(major, minor, patch);
      // avoid dependency on libGraf and hard code, will not change too often
      major = 2; minor = 1; patch = 3;
      Printf("\nFreeType Engine v%d.%d.%d used to render TrueType fonts.",
             major, minor, patch);
   }
#ifdef _REENTRANT
   else
      printf("\n");
   Printf("Compiled for %s with thread support.", gSystem->GetBuildArch());
#else
   else
      printf("\n");
   Printf("Compiled for %s.", gSystem->GetBuildArch());
#endif

   gInterpreter->PrintIntro();

#ifdef R__UNIX
   // Popdown X logo, only if started with -splash option
   for (int i = 0; i < Argc(); i++)
      if (!strcmp(Argv(i), "-splash"))
         kill(getppid(), SIGUSR1);
#endif
}

//______________________________________________________________________________
char *TRint::GetPrompt()
{
   // Get prompt from interpreter. Either "root [n]" or "end with '}'".

   char *s = gInterpreter->GetPrompt();
   if (s[0])
      strcpy(fPrompt, s);
   else
      sprintf(fPrompt, fDefaultPrompt.Data(), fNcmd);

   return fPrompt;
}

//______________________________________________________________________________
const char *TRint::SetPrompt(const char *newPrompt)
{
   // Set a new default prompt. It returns the previous prompt.
   // The prompt may contain a %d which will be replaced by the commend
   // number. The default prompt is "root [%d] ". The maximum length of
   // the prompt is 55 characters. To set the prompt in an interactive
   // session do:
   // root [0] ((TRint*)gROOT->GetApplication())->SetPrompt("aap> ")
   // aap>

   static TString op = fDefaultPrompt;

   if (newPrompt && strlen(newPrompt) <= 55)
      fDefaultPrompt = newPrompt;
   else
      Error("SetPrompt", "newPrompt too long (> 55 characters)");

   return op.Data();
}

//______________________________________________________________________________
Bool_t TRint::HandleTermInput()
{
   // Handle input coming from terminal.

   static TStopwatch timer;
   char *line;

   if ((line = Getlinem(kOneChar, 0))) {
      if (line[0] == 0 && Gl_eof())
         Terminate(0);

      gVirtualX->SetKeyAutoRepeat(kTRUE);

      Gl_histadd(line);

      TString sline = line;
      line[0] = 0;

      // strip off '\n' and leading and trailing blanks
      sline = sline.Chop();
      sline = sline.Strip(TString::kBoth);
      ReturnPressed((char*)sline.Data());

      fInterrupt = kFALSE;

      if (!gInterpreter->GetMore() && !sline.IsNull()) fNcmd++;

      // prevent recursive calling of this input handler
      fInputHandler->DeActivate();

      if (gROOT->Timer()) timer.Start();

      Bool_t added = kFALSE;
#ifdef R__EH
      try {
#endif
         TRY {
            ProcessLine(sline);
         } CATCH(excode) {
            // enable again input handler
            fInputHandler->Activate();
            added = kTRUE;
            Throw(excode);
         } ENDTRY;
#ifdef R__EH
      }
      // handle every exception
      catch (...) {
         // enable again intput handler
         if (!added) fInputHandler->Activate();
         throw;
      }
#endif

      if (gROOT->Timer()) timer.Print("u");

      // enable again intput handler
      fInputHandler->Activate();

      if (!sline.BeginsWith(".reset"))
         gInterpreter->EndOfLineAction();

      gTabCom->ClearAll();
      Getlinem(kInit, GetPrompt());
   }
   return kTRUE;
}

//______________________________________________________________________________
void TRint::Terminate(Int_t status)
{
   // Terminate the application. Reset the terminal to sane mode and call
   // the logoff macro defined via Rint.Logoff environment variable.

   Getlinem(kCleanUp, 0);

   if (ReturnFromRun()) {
      gSystem->ExitLoop();
   } else {
      //Execute logoff macro
      const char *logoff;
      logoff = gEnv->GetValue("Rint.Logoff", (char*)0);
      if (logoff && !NoLogOpt()) {
         char *mac = gSystem->Which(TROOT::GetMacroPath(), logoff, kReadPermission);
         if (mac)
            ProcessFile(logoff);
         delete [] mac;
      }

      gSystem->Exit(status);
   }
}

//______________________________________________________________________________
void TRint::SetEchoMode(Bool_t mode)
{
   // Set console mode:
   //
   //  mode = kTRUE  - echo input symbols
   //  mode = kFALSE - noecho input symbols

   Gl_config("noecho", mode ? 0 : 1);
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
#include "parser.h"
#include "tokenize.h"

// Extended BEDMAS precedence order
int precedence(Node tok) {
    std::string v = tok.val;
    if (v == "!" || v == "not") return 0;
    else if (v=="^" || v == "**") return 1;
	else if (v=="*" || v=="/" || v=="@/" || v=="%" || v=="@%") return 2;
    else if (v=="+" || v=="-") return 3;
    else if (v=="<" || v==">" || v=="<=" || v==">=") return 4;
    else if (v=="@<" || v=="@>" || v=="@<=" || v=="@>=") return 4;
    else if (v=="&" || v=="|" || v=="xor" || v=="==" || v == "!=") return 5;
    else if (v=="&&" || v=="and") return 6;
    else if (v=="||" || v=="or") return 7;
    else if (v==":") return 8;
    else if (v=="=") return 10;
    else if (v=="+=" || v=="-=" || v=="*=" || v=="/=" || v=="%=") return 10;
    else if (v=="@/=" || v=="@%=") return 10;
    else return -1;
}

// Token classification for shunting-yard purposes
int toktype(Node tok) {
    if (tok.type == ASTNODE) return COMPOUND;
    std::string v = tok.val;
    if (v == "(" || v == "[" || v == "{") return LPAREN;
    else if (v == ")" || v == "]" || v == "}") return RPAREN;
    else if (v == ",") return COMMA;
    else if (v == "!" || v == "not") return UNARY_OP;
    else if (precedence(tok) >= 0) return BINARY_OP;
    if (tok.val[0] != '"' && tok.val[0] != '\'') {
		for (unsigned i = 0; i < tok.val.length(); i++) {
            if (chartype(tok.val[i]) == SYMB) {
                err("Invalid symbol: "+tok.val, tok.metadata);
            }
        }
    }
    return ALPHANUM;
}

// Converts to reverse polish notation
std::vector<Node> shuntingYard(std::vector<Node> tokens) {
    std::vector<Node> iq;
    for (int i = tokens.size() - 1; i >= 0; i--) {
        iq.push_back(tokens[i]);
    }
    std::vector<Node> oq;
    std::vector<Node> stack;
    Node prev, tok;
    int prevtyp = 0, toktyp = 0;

    while (iq.size()) {
        prev = tok;
        prevtyp = toktyp;
        tok = iq.back();
        toktyp = toktype(tok);
        iq.pop_back();
        // Alphanumerics go straight to output queue
        if (toktyp == ALPHANUM) {
            oq.push_back(tok);
        }
        // Left parens go on stack and output queue
        else if (toktyp == LPAREN) {
            if (prevtyp != ALPHANUM && prevtyp != RPAREN) {
                oq.push_back(token("id", tok.metadata));
            }
            stack.push_back(tok);
            oq.push_back(tok);
        }
        // If rparen, keep moving from stack to output queue until lparen
        else if (toktyp == RPAREN) {
            while (stack.size() && toktype(stack.back()) != LPAREN) {
                oq.push_back(stack.back());
                stack.pop_back();
            }
            if (stack.size()) {
                stack.pop_back();
            }
            oq.push_back(tok);
        }
        // If binary op, keep popping from stack while higher bedmas precedence
        else if (toktyp == UNARY_OP || toktyp == BINARY_OP) {
            if (tok.val == "-" && prevtyp != ALPHANUM && prevtyp != RPAREN) {
                oq.push_back(token("0", tok.metadata));
            }
            int prec = precedence(tok);
            while (stack.size()
                  && (toktype(stack.back()) == BINARY_OP
                      || toktype(stack.back()) == UNARY_OP)
                  && precedence(stack.back()) <= prec) {
                oq.push_back(stack.back());
                stack.pop_back();
            }
            stack.push_back(tok);
        }
        // Comma means finish evaluating the argument
        else if (toktyp == COMMA) {
            while (stack.size() && toktype(stack.back()) != LPAREN) {
                oq.push_back(stack.back());
                stack.pop_back();
            }
        }
    }
    while (stack.size()) {
        oq.push_back(stack.back());
        stack.pop_back();
    }
    return oq;
}

// Converts reverse polish notation into tree
Node treefy(std::vector<Node> stream) {
    std::vector<Node> iq;
    for (int i = stream.size() -1; i >= 0; i--) {
        iq.push_back(stream[i]);
    }
    std::vector<Node> oq;
    while (iq.size()) {
        Node tok = iq.back();
        iq.pop_back();
        int typ = toktype(tok);
        // If unary, take node off end of oq and wrap it with the operator
        // If binary, do the same with two nodes
        if (typ == UNARY_OP || typ == BINARY_OP) {
            std::vector<Node> args;
            int rounds = (typ == BINARY_OP) ? 2 : 1;
            for (int i = 0; i < rounds; i++) {
                if (oq.size() == 0) {
                    err("Line malformed, not enough args for "+tok.val,
                        tok.metadata);
                }
                args.push_back(oq.back());
                oq.pop_back();
            }
            std::vector<Node> args2;
            while (args.size()) {
                args2.push_back(args.back());
                args.pop_back();
            }
            oq.push_back(astnode(tok.val, args2, tok.metadata));
        }
        // If rparen, keep grabbing until we get to an lparen
        else if (typ == RPAREN) {
            std::vector<Node> args;
            while (1) {
                if (toktype(oq.back()) == LPAREN) break;
                args.push_back(oq.back());
                oq.pop_back();
                if (!oq.size()) err("Bracket without matching", tok.metadata);
            }
            oq.pop_back();
            args.push_back(oq.back());
            oq.pop_back();
            // We represent a[b] as (access a b)
            if (tok.val == "]")
                 args.push_back(token("access", tok.metadata));
            if (args.back().type == ASTNODE)
                 args.push_back(token("fun", tok.metadata));
            std::string fun = args.back().val;
            args.pop_back();
            // We represent [1,2,3] as (array_lit 1 2 3)
            if (fun == "access" && args.size() && args.back().val == "id") {
                fun = "array_lit";
                args.pop_back();
            }
            std::vector<Node> args2;
            while (args.size()) {
                args2.push_back(args.back());
                args.pop_back();
            }
            // When evaluating 2 + (3 * 5), the shunting yard algo turns that
            // into 2 ( id 3 5 * ) +, effectively putting "id" as a dummy
            // function where the algo was expecting a function to call the
            // thing inside the brackets. This reverses that step
			if (fun == "id" && args2.size() == 1) {
                oq.push_back(args2[0]);
            }
            else {
                oq.push_back(astnode(fun, args2, tok.metadata));
            }
        }
        else oq.push_back(tok);
        // This is messy, but has to be done. Import/inset other files here
        std::string v = oq.back().val;
        if ((v == "inset" || v == "import" || v == "create")
                && oq.back().args.size() == 1
                && oq.back().args[0].type == TOKEN) {
            int lastSlashPos = tok.metadata.file.rfind("/");
            std::string root;
            if (lastSlashPos >= 0)
                root = tok.metadata.file.substr(0, lastSlashPos) + "/";
            else
                root = "";
            std::string filename = oq.back().args[0].val;
            filename = filename.substr(1, filename.length() - 2);
            if (!exists(root + filename))
                err("File does not exist: "+root + filename, tok.metadata);
            oq.back().args.pop_back();
            oq.back().args.push_back(parseSerpent(root + filename));
        }
        //Useful for debugging
        //for (int i = 0; i < oq.size(); i++) {
        //    std::cerr << printSimple(oq[i]) << " ";
        //}
        //std::cerr << " <-\n";
    }
    // Output must have one argument
    if (oq.size() == 0) {
        err("Output blank", Metadata());
    }
    else if (oq.size() > 1) {
        err("Multiple expressions or unclosed bracket", oq[1].metadata);
    }

	return oq[0];
}

// Parses one line of serpent
Node parseSerpentTokenStream(std::vector<Node> s) {
    return treefy(shuntingYard(s));
}

// Count spaces at beginning of line
int spaceCount(std::string s) {
	unsigned pos = 0;
	while (pos < s.length() && (s[pos] == ' ' || s[pos] == '\t'))
		pos++;
    return pos;
}

// Is this a command that takes an argument on the same line?
bool bodied(std::string tok) {
    return tok == "if" || tok == "elif" || tok == "while";
}

// Is this a command that takes an argument as a child block?
bool childBlocked(std::string tok) {
    return tok == "if" || tok == "elif" || tok == "else"
        || tok == "code" || tok == "shared" || tok == "init"
        || tok == "while" || tok == "repeat" || tok == "for";
}

// Are the two commands meant to continue each other?
bool bodiedContinued(std::string prev, std::string tok) {
    return (prev == "if" && tok == "elif")
        || (prev == "elif" && tok == "else")
        || (prev == "elif" && tok == "elif")
        || (prev == "if" && tok == "else")
        || (prev == "init" && tok == "code")
        || (prev == "shared" && tok == "code")
        || (prev == "shared" && tok == "init");
}

// Is a line of code empty?
bool isLineEmpty(std::string line) {
    std::vector<Node> tokens = tokenize(line);
    if (!tokens.size() || tokens[0].val == "#" || tokens[0].val == "//")
        return true;
    return false;
}

// Parse lines of serpent (helper function)
Node parseLines(std::vector<std::string> lines, Metadata metadata, int sp) {
    std::vector<Node> o;
    int origLine = metadata.ln;
	unsigned i = 0;
    while (i < lines.size()) {
        metadata.ln = origLine + i;
        std::string main = lines[i];
        if (isLineEmpty(main)) {
            i += 1;
            continue;
        }
        int spaces = spaceCount(main);
        if (spaces != sp) {
            err("Indent mismatch", metadata);
        }
        // Tokenize current line
        std::vector<Node> tokens = tokenize(main.substr(sp), metadata);
        // Remove extraneous tokens, including if / elif
        std::vector<Node> tokens2;
		for (unsigned j = 0; j < tokens.size(); j++) {
            if (tokens[j].val == "#" || tokens[j].val == "//") break;
            if (j >= 1 || !bodied(tokens[j].val)) {
                tokens2.push_back(tokens[j]);
            }
        }
        if (tokens2.size() > 0 && tokens2.back().val == ":")
            tokens2.pop_back();
        // Parse current line
        Node out = parseSerpentTokenStream(tokens2);
        // Parse child block
        int childIndent = 999999;
        std::vector<std::string> childBlock;
        while (1) {
			i++;
			if (i >= lines.size())
				break;
            bool ile = isLineEmpty(lines[i]);
            if (!ile) {
                int spaces = spaceCount(lines[i]);
                if (spaces <= sp) break;
                childBlock.push_back(lines[i]);
                if (spaces < childIndent) childIndent = spaces;
            }
            else childBlock.push_back("");
        }
        // Child block empty?
        bool cbe = true;
		for (unsigned i = 0; i < childBlock.size(); i++) {
            if (childBlock[i].length() > 0) { cbe = false; break; }
        }
        // Bring back if / elif into AST
        if (bodied(tokens[0].val)) {
            std::vector<Node> args;
            args.push_back(out);
            out = astnode(tokens[0].val, args, out.metadata);
        }
        // Add child block to AST
        if (childBlocked(tokens[0].val)) {
            if (cbe)
                err("Expected indented child block!", out.metadata);
            out.type = ASTNODE;
            metadata.ln += 1;
            out.args.push_back(parseLines(childBlock, metadata, childIndent));
            metadata.ln -= 1;
        }
        else if (!cbe)
            err("Did not expect indented child block!", out.metadata);
        if (o.size() == 0 || o.back().type == TOKEN) {
            o.push_back(out);
            continue;
        }
        // This is a little complicated. Basically, the idea here is to build
        // constructions like [if [< x 5] [a] [elif [< x 10] [b] [else [c]]]]
        std::vector<Node> u;
        u.push_back(o.back());
        if (bodiedContinued(o.back().val, out.val)) {
            while (1) {
                if (!bodiedContinued(u.back().val, out.val)) {
                    u.pop_back();
                    break;
                }
                if (!u.back().args.size()
                 || !bodiedContinued(u.back().val, u.back().args.back().val)) {
                    break;
                }
                u.push_back(u.back().args.back());
            }
            u.back().args.push_back(out);
            while (u.size() > 1) {
                Node v = u.back();
                u.pop_back();
                u.back().args.pop_back();
                u.back().args.push_back(v);
            }
            o.pop_back();
            o.push_back(u[0]);
        }
        else o.push_back(out);
    }
	if (o.size() == 1)
		return o[0];
	else if (o.size())
		return astnode("seq", o, o[0].metadata);
	else
		return astnode("seq", o, Metadata());
}

// Parses serpent code
Node parseSerpent(std::string s) {
    std::string input = s;
    std::string file = "main";
    if (exists(s)) {
        file = s;
        input = get_file_contents(s);
    }
    return parseLines(splitLines(input), Metadata(file, 0, 0), 0);
}

using namespace std;
<commit_msg>Fixed a bug in treefy() that tried to access vector oq before making sure it's not empty<commit_after>#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "util.h"
#include "parser.h"
#include "tokenize.h"

// Extended BEDMAS precedence order
int precedence(Node tok) {
    std::string v = tok.val;
    if (v == "!" || v == "not") return 0;
    else if (v=="^" || v == "**") return 1;
	else if (v=="*" || v=="/" || v=="@/" || v=="%" || v=="@%") return 2;
    else if (v=="+" || v=="-") return 3;
    else if (v=="<" || v==">" || v=="<=" || v==">=") return 4;
    else if (v=="@<" || v=="@>" || v=="@<=" || v=="@>=") return 4;
    else if (v=="&" || v=="|" || v=="xor" || v=="==" || v == "!=") return 5;
    else if (v=="&&" || v=="and") return 6;
    else if (v=="||" || v=="or") return 7;
    else if (v==":") return 8;
    else if (v=="=") return 10;
    else if (v=="+=" || v=="-=" || v=="*=" || v=="/=" || v=="%=") return 10;
    else if (v=="@/=" || v=="@%=") return 10;
    else return -1;
}

// Token classification for shunting-yard purposes
int toktype(Node tok) {
    if (tok.type == ASTNODE) return COMPOUND;
    std::string v = tok.val;
    if (v == "(" || v == "[" || v == "{") return LPAREN;
    else if (v == ")" || v == "]" || v == "}") return RPAREN;
    else if (v == ",") return COMMA;
    else if (v == "!" || v == "not") return UNARY_OP;
    else if (precedence(tok) >= 0) return BINARY_OP;
    if (tok.val[0] != '"' && tok.val[0] != '\'') {
		for (unsigned i = 0; i < tok.val.length(); i++) {
            if (chartype(tok.val[i]) == SYMB) {
                err("Invalid symbol: "+tok.val, tok.metadata);
            }
        }
    }
    return ALPHANUM;
}

// Converts to reverse polish notation
std::vector<Node> shuntingYard(std::vector<Node> tokens) {
    std::vector<Node> iq;
    for (int i = tokens.size() - 1; i >= 0; i--) {
        iq.push_back(tokens[i]);
    }
    std::vector<Node> oq;
    std::vector<Node> stack;
    Node prev, tok;
    int prevtyp = 0, toktyp = 0;

    while (iq.size()) {
        prev = tok;
        prevtyp = toktyp;
        tok = iq.back();
        toktyp = toktype(tok);
        iq.pop_back();
        // Alphanumerics go straight to output queue
        if (toktyp == ALPHANUM) {
            oq.push_back(tok);
        }
        // Left parens go on stack and output queue
        else if (toktyp == LPAREN) {
            if (prevtyp != ALPHANUM && prevtyp != RPAREN) {
                oq.push_back(token("id", tok.metadata));
            }
            stack.push_back(tok);
            oq.push_back(tok);
        }
        // If rparen, keep moving from stack to output queue until lparen
        else if (toktyp == RPAREN) {
            while (stack.size() && toktype(stack.back()) != LPAREN) {
                oq.push_back(stack.back());
                stack.pop_back();
            }
            if (stack.size()) {
                stack.pop_back();
            }
            oq.push_back(tok);
        }
        // If binary op, keep popping from stack while higher bedmas precedence
        else if (toktyp == UNARY_OP || toktyp == BINARY_OP) {
            if (tok.val == "-" && prevtyp != ALPHANUM && prevtyp != RPAREN) {
                oq.push_back(token("0", tok.metadata));
            }
            int prec = precedence(tok);
            while (stack.size()
                  && (toktype(stack.back()) == BINARY_OP
                      || toktype(stack.back()) == UNARY_OP)
                  && precedence(stack.back()) <= prec) {
                oq.push_back(stack.back());
                stack.pop_back();
            }
            stack.push_back(tok);
        }
        // Comma means finish evaluating the argument
        else if (toktyp == COMMA) {
            while (stack.size() && toktype(stack.back()) != LPAREN) {
                oq.push_back(stack.back());
                stack.pop_back();
            }
        }
    }
    while (stack.size()) {
        oq.push_back(stack.back());
        stack.pop_back();
    }
    return oq;
}

// Converts reverse polish notation into tree
Node treefy(std::vector<Node> stream) {
    std::vector<Node> iq;
    for (int i = stream.size() -1; i >= 0; i--) {
        iq.push_back(stream[i]);
    }
    std::vector<Node> oq;
    while (iq.size()) {
        Node tok = iq.back();
        iq.pop_back();
        int typ = toktype(tok);
        // If unary, take node off end of oq and wrap it with the operator
        // If binary, do the same with two nodes
        if (typ == UNARY_OP || typ == BINARY_OP) {
            std::vector<Node> args;
            int rounds = (typ == BINARY_OP) ? 2 : 1;
            for (int i = 0; i < rounds; i++) {
                if (oq.size() == 0) {
                    err("Line malformed, not enough args for "+tok.val,
                        tok.metadata);
                }
                args.push_back(oq.back());
                oq.pop_back();
            }
            std::vector<Node> args2;
            while (args.size()) {
                args2.push_back(args.back());
                args.pop_back();
            }
            oq.push_back(astnode(tok.val, args2, tok.metadata));
        }
        // If rparen, keep grabbing until we get to an lparen
        else if (typ == RPAREN) {
            std::vector<Node> args;
            while (1) {
                if (!oq.size()) err("Bracket without matching", tok.metadata);
                if (toktype(oq.back()) == LPAREN) break;
                args.push_back(oq.back());
                oq.pop_back();
            }
            oq.pop_back();
            args.push_back(oq.back());
            oq.pop_back();
            // We represent a[b] as (access a b)
            if (tok.val == "]")
                 args.push_back(token("access", tok.metadata));
            if (args.back().type == ASTNODE)
                 args.push_back(token("fun", tok.metadata));
            std::string fun = args.back().val;
            args.pop_back();
            // We represent [1,2,3] as (array_lit 1 2 3)
            if (fun == "access" && args.size() && args.back().val == "id") {
                fun = "array_lit";
                args.pop_back();
            }
            std::vector<Node> args2;
            while (args.size()) {
                args2.push_back(args.back());
                args.pop_back();
            }
            // When evaluating 2 + (3 * 5), the shunting yard algo turns that
            // into 2 ( id 3 5 * ) +, effectively putting "id" as a dummy
            // function where the algo was expecting a function to call the
            // thing inside the brackets. This reverses that step
			if (fun == "id" && args2.size() == 1) {
                oq.push_back(args2[0]);
            }
            else {
                oq.push_back(astnode(fun, args2, tok.metadata));
            }
        }
        else oq.push_back(tok);
        // This is messy, but has to be done. Import/inset other files here
        std::string v = oq.back().val;
        if ((v == "inset" || v == "import" || v == "create")
                && oq.back().args.size() == 1
                && oq.back().args[0].type == TOKEN) {
            int lastSlashPos = tok.metadata.file.rfind("/");
            std::string root;
            if (lastSlashPos >= 0)
                root = tok.metadata.file.substr(0, lastSlashPos) + "/";
            else
                root = "";
            std::string filename = oq.back().args[0].val;
            filename = filename.substr(1, filename.length() - 2);
            if (!exists(root + filename))
                err("File does not exist: "+root + filename, tok.metadata);
            oq.back().args.pop_back();
            oq.back().args.push_back(parseSerpent(root + filename));
        }
        //Useful for debugging
        //for (int i = 0; i < oq.size(); i++) {
        //    std::cerr << printSimple(oq[i]) << " ";
        //}
        //std::cerr << " <-\n";
    }
    // Output must have one argument
    if (oq.size() == 0) {
        err("Output blank", Metadata());
    }
    else if (oq.size() > 1) {
        err("Multiple expressions or unclosed bracket", oq[1].metadata);
    }

	return oq[0];
}

// Parses one line of serpent
Node parseSerpentTokenStream(std::vector<Node> s) {
    return treefy(shuntingYard(s));
}

// Count spaces at beginning of line
int spaceCount(std::string s) {
	unsigned pos = 0;
	while (pos < s.length() && (s[pos] == ' ' || s[pos] == '\t'))
		pos++;
    return pos;
}

// Is this a command that takes an argument on the same line?
bool bodied(std::string tok) {
    return tok == "if" || tok == "elif" || tok == "while";
}

// Is this a command that takes an argument as a child block?
bool childBlocked(std::string tok) {
    return tok == "if" || tok == "elif" || tok == "else"
        || tok == "code" || tok == "shared" || tok == "init"
        || tok == "while" || tok == "repeat" || tok == "for";
}

// Are the two commands meant to continue each other?
bool bodiedContinued(std::string prev, std::string tok) {
    return (prev == "if" && tok == "elif")
        || (prev == "elif" && tok == "else")
        || (prev == "elif" && tok == "elif")
        || (prev == "if" && tok == "else")
        || (prev == "init" && tok == "code")
        || (prev == "shared" && tok == "code")
        || (prev == "shared" && tok == "init");
}

// Is a line of code empty?
bool isLineEmpty(std::string line) {
    std::vector<Node> tokens = tokenize(line);
    if (!tokens.size() || tokens[0].val == "#" || tokens[0].val == "//")
        return true;
    return false;
}

// Parse lines of serpent (helper function)
Node parseLines(std::vector<std::string> lines, Metadata metadata, int sp) {
    std::vector<Node> o;
    int origLine = metadata.ln;
	unsigned i = 0;
    while (i < lines.size()) {
        metadata.ln = origLine + i;
        std::string main = lines[i];
        if (isLineEmpty(main)) {
            i += 1;
            continue;
        }
        int spaces = spaceCount(main);
        if (spaces != sp) {
            err("Indent mismatch", metadata);
        }
        // Tokenize current line
        std::vector<Node> tokens = tokenize(main.substr(sp), metadata);
        // Remove extraneous tokens, including if / elif
        std::vector<Node> tokens2;
		for (unsigned j = 0; j < tokens.size(); j++) {
            if (tokens[j].val == "#" || tokens[j].val == "//") break;
            if (j >= 1 || !bodied(tokens[j].val)) {
                tokens2.push_back(tokens[j]);
            }
        }
        if (tokens2.size() > 0 && tokens2.back().val == ":")
            tokens2.pop_back();
        // Parse current line
        Node out = parseSerpentTokenStream(tokens2);
        // Parse child block
        int childIndent = 999999;
        std::vector<std::string> childBlock;
        while (1) {
			i++;
			if (i >= lines.size())
				break;
            bool ile = isLineEmpty(lines[i]);
            if (!ile) {
                int spaces = spaceCount(lines[i]);
                if (spaces <= sp) break;
                childBlock.push_back(lines[i]);
                if (spaces < childIndent) childIndent = spaces;
            }
            else childBlock.push_back("");
        }
        // Child block empty?
        bool cbe = true;
		for (unsigned i = 0; i < childBlock.size(); i++) {
            if (childBlock[i].length() > 0) { cbe = false; break; }
        }
        // Bring back if / elif into AST
        if (bodied(tokens[0].val)) {
            std::vector<Node> args;
            args.push_back(out);
            out = astnode(tokens[0].val, args, out.metadata);
        }
        // Add child block to AST
        if (childBlocked(tokens[0].val)) {
            if (cbe)
                err("Expected indented child block!", out.metadata);
            out.type = ASTNODE;
            metadata.ln += 1;
            out.args.push_back(parseLines(childBlock, metadata, childIndent));
            metadata.ln -= 1;
        }
        else if (!cbe)
            err("Did not expect indented child block!", out.metadata);
        if (o.size() == 0 || o.back().type == TOKEN) {
            o.push_back(out);
            continue;
        }
        // This is a little complicated. Basically, the idea here is to build
        // constructions like [if [< x 5] [a] [elif [< x 10] [b] [else [c]]]]
        std::vector<Node> u;
        u.push_back(o.back());
        if (bodiedContinued(o.back().val, out.val)) {
            while (1) {
                if (!bodiedContinued(u.back().val, out.val)) {
                    u.pop_back();
                    break;
                }
                if (!u.back().args.size()
                 || !bodiedContinued(u.back().val, u.back().args.back().val)) {
                    break;
                }
                u.push_back(u.back().args.back());
            }
            u.back().args.push_back(out);
            while (u.size() > 1) {
                Node v = u.back();
                u.pop_back();
                u.back().args.pop_back();
                u.back().args.push_back(v);
            }
            o.pop_back();
            o.push_back(u[0]);
        }
        else o.push_back(out);
    }
	if (o.size() == 1)
		return o[0];
	else if (o.size())
		return astnode("seq", o, o[0].metadata);
	else
		return astnode("seq", o, Metadata());
}

// Parses serpent code
Node parseSerpent(std::string s) {
    std::string input = s;
    std::string file = "main";
    if (exists(s)) {
        file = s;
        input = get_file_contents(s);
    }
    return parseLines(splitLines(input), Metadata(file, 0, 0), 0);
}

using namespace std;
<|endoftext|>


<commit_before>#include <iostream>
#include "../inanity-base.hpp"
#include "../inanity-platform.hpp"
#include "Font.hpp"
#include "FtEngine.hpp"
#include "FontFace.hpp"
#include "SwCanvas.hpp"
#include "FontGlyphs.hpp"
#include "../graphics/RawTextureData.hpp"
using namespace Inanity;
using namespace Inanity::Graphics;

void SaveToBmp(ptr<RawTextureData> rawTextureData, ptr<OutputStream> outputStream)
{
	int width = rawTextureData->GetMipWidth();
	int height = rawTextureData->GetMipHeight();
	int pitch = (width + 3) & ~3;

	BITMAPFILEHEADER bfh;
	bfh.bfType = 'MB';
	bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD) + pitch * height;
	bfh.bfReserved1 = 0;
	bfh.bfReserved2 = 0;
	bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
	outputStream->Write(&bfh, sizeof(bfh));

	BITMAPINFOHEADER bih;
	memset(&bih, 0, sizeof(bih));
	bih.biSize = sizeof(bih);
	bih.biWidth = width;
	bih.biHeight = height;
	bih.biPlanes = 1;
	bih.biBitCount = 8;
	outputStream->Write(&bih, sizeof(bih));

	RGBQUAD palette[256];
	for(int i = 0; i < 256; ++i)
	{
		palette[i].rgbBlue = i;
		palette[i].rgbGreen = i;
		palette[i].rgbRed = i;
		palette[i].rgbReserved = 0;
	}
	outputStream->Write(palette, sizeof(palette));

	const char* data = (const char*)rawTextureData->GetMipData();
	for(int i = height - 1; i >= 0; --i)
		outputStream->Write(data + i * width, pitch);
}

int main()
{
	try
	{
		ptr<FileSystem> fs = NEW(Platform::FileSystem(""));
		ptr<Gui::FontEngine> fontEngine = NEW(Gui::FtEngine());
		ptr<Gui::FontFace> fontFace = fontEngine->LoadFontFace(fs->LoadFile("gui/DejaVuSans.ttf"));
		const int fontSize = 64;
		ptr<Gui::FontShape> fontShape = fontFace->CreateShape(fontSize);
		ptr<Gui::SwCanvas> canvas = NEW(Gui::SwCanvas());
		ptr<Gui::FontGlyphs> fontGlyphs = fontFace->CreateGlyphs(canvas, fontSize);

		ptr<Gui::Font> font = NEW(Gui::Font(fontShape, fontGlyphs));

		const int destWidth = 1024;
		const int destHeight = 1024;
		const PixelFormat pixelFormat = PixelFormat(PixelFormat::pixelR, PixelFormat::formatUint, PixelFormat::size8bit);
		ptr<RawTextureData> image = NEW(RawTextureData(
			NEW(MemoryFile(destWidth * destHeight * PixelFormat::GetPixelSize(pixelFormat.size))),
			pixelFormat,
			destWidth,
			destHeight,
			0, // depth
			1, // mips
			0 // count
			));
		memset(image->GetMipData(), 128, image->GetImageSize());

		canvas->SetDestination(image);
		font->DrawString(canvas, "Inanity", vec2(100, 500));

		SaveToBmp(image, fs->SaveStream("gui/out.bmp"));
	}
	catch(Exception* exception)
	{
		MakePointer(exception)->PrintStack(std::cout);
	}

	return 0;
}
<commit_msg>fixes for testft test program<commit_after>#include <iostream>
#include "../inanity-base.hpp"
#include "../inanity-platform.hpp"
#include "Font.hpp"
#include "FtEngine.hpp"
#include "FontFace.hpp"
#include "SwCanvas.hpp"
#include "SwFontGlyphs.hpp"
#include "FontGlyphs.hpp"
#include "../graphics/RawTextureData.hpp"
using namespace Inanity;
using namespace Inanity::Graphics;

void SaveToBmp(ptr<RawTextureData> rawTextureData, ptr<OutputStream> outputStream)
{
	int width = rawTextureData->GetMipWidth();
	int height = rawTextureData->GetMipHeight();
	int sourcePitch = rawTextureData->GetMipLinePitch();
	int pixelSize = rawTextureData->GetPixelSize();
	int pitch = (width * pixelSize + 3) & ~3;

	BITMAPFILEHEADER bfh;
	bfh.bfType = 'MB';
	bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (pixelSize == 1 ? 256 * sizeof(RGBQUAD) : 0) + pitch * height;
	bfh.bfReserved1 = 0;
	bfh.bfReserved2 = 0;
	bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (pixelSize == 1 ? 256 * sizeof(RGBQUAD) : 0);
	outputStream->Write(&bfh, sizeof(bfh));

	BITMAPINFOHEADER bih;
	memset(&bih, 0, sizeof(bih));
	bih.biSize = sizeof(bih);
	bih.biWidth = width;
	bih.biHeight = height;
	bih.biPlanes = 1;
	bih.biBitCount = pixelSize * 8;
	outputStream->Write(&bih, sizeof(bih));

	if(pixelSize == 1)
	{
		RGBQUAD palette[256];
		for(int i = 0; i < 256; ++i)
		{
			palette[i].rgbBlue = i;
			palette[i].rgbGreen = i;
			palette[i].rgbRed = i;
			palette[i].rgbReserved = 0;
		}
		outputStream->Write(palette, sizeof(palette));
	}

	const char* data = (const char*)rawTextureData->GetMipData();
	for(int i = height - 1; i >= 0; --i)
		outputStream->Write(data + i * sourcePitch, pitch);
}

int main()
{
	try
	{
		ptr<FileSystem> fs = NEW(Platform::FileSystem(""));
		ptr<Gui::FontEngine> fontEngine = NEW(Gui::FtEngine());
		ptr<Gui::FontFace> fontFace = fontEngine->LoadFontFace(fs->LoadFile("gui/DejaVuSans.ttf"));
		const int fontSize = 13;
		ptr<Gui::FontShape> fontShape = fontFace->CreateShape(fontSize);
		ptr<Gui::SwCanvas> canvas = NEW(Gui::SwCanvas());
		ptr<Gui::FontGlyphs> fontGlyphs = fontFace->CreateGlyphs(canvas, fontSize);

		SaveToBmp(fontGlyphs.FastCast<Gui::SwFontGlyphs>()->GetImage(), fs->SaveStream("gui/alphabat.bmp"));

		ptr<Gui::Font> font = NEW(Gui::Font(fontShape, fontGlyphs));

		const int destWidth = 1024;
		const int destHeight = 1024;
		const PixelFormat pixelFormat = PixelFormat(PixelFormat::pixelR, PixelFormat::formatUint, PixelFormat::size24bit);
		ptr<RawTextureData> image = NEW(RawTextureData(
			NEW(MemoryFile(destWidth * destHeight * PixelFormat::GetPixelSize(pixelFormat.size))),
			pixelFormat,
			destWidth,
			destHeight,
			0, // depth
			1, // mips
			0 // count
			));
		memset(image->GetMipData(), 255, image->GetImageSize());

		canvas->SetDestination(image);
		font->DrawString(canvas, "Inanity", vec2(100.0f, 500.0f), vec4(0, 0, 0, 1));

		SaveToBmp(image, fs->SaveStream("gui/out.bmp"));
	}
	catch(Exception* exception)
	{
		MakePointer(exception)->PrintStack(std::cout);
	}

	return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: dlgedfac.cxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#include "precompiled_reportdesign.hxx"
#include "dlgedfac.hxx"
#ifndef REPORTDESIGN_SHARED_UISTRINGS_HRC
#include "uistrings.hrc"
#endif
#include "RptObject.hxx"
#include <RptDef.hxx>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/awt/ScrollBarOrientation.hpp>
#include <svx/svdoole2.hxx>
namespace rptui
{
using namespace ::com::sun::star;

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

DlgEdFactory::DlgEdFactory()
{
    SdrObjFactory::InsertMakeObjectHdl( LINK(this, DlgEdFactory, MakeObject) );
}

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

DlgEdFactory::~DlgEdFactory()
{
    SdrObjFactory::RemoveMakeObjectHdl( LINK(this, DlgEdFactory, MakeObject) );
}

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

IMPL_LINK( DlgEdFactory, MakeObject, SdrObjFactory *, pObjFactory )
{
    if ( pObjFactory->nInventor == ReportInventor )
    {
        switch( pObjFactory->nIdentifier )
        {
            case OBJ_DLG_FIXEDTEXT:
                    pObjFactory->pNewObj = new OUnoObject( SERVICE_FIXEDTEXT
                                                        ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.form.component.FixedText"))
                                                        ,OBJ_DLG_FIXEDTEXT);
                    break;
            case OBJ_DLG_IMAGECONTROL:
                    pObjFactory->pNewObj = new OUnoObject( SERVICE_IMAGECONTROL
                                                        ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.form.component.DatabaseImageControl"))
                                                        ,OBJ_DLG_IMAGECONTROL);
                    break;
            case OBJ_DLG_FORMATTEDFIELD:
                    pObjFactory->pNewObj = new OUnoObject( SERVICE_FORMATTEDFIELD
                                                        ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.form.component.FormattedField"))
                                                        ,OBJ_DLG_FORMATTEDFIELD);
                    break;
            case OBJ_DLG_VFIXEDLINE:
            case OBJ_DLG_HFIXEDLINE:
                {
                    OUnoObject* pObj = new OUnoObject( SERVICE_FIXEDLINE
                                                        ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.UnoControlFixedLineModel"))
                                                        ,pObjFactory->nIdentifier);
                    pObjFactory->pNewObj = pObj;
                    if ( pObjFactory->nIdentifier == OBJ_DLG_HFIXEDLINE )
                    {
                        uno::Reference<beans::XPropertySet> xProp = pObj->getAwtComponent();
                        xProp->setPropertyValue( PROPERTY_ORIENTATION, uno::makeAny(sal_Int32(0)) );
                    }
                }
                break;
            case OBJ_CUSTOMSHAPE:
                pObjFactory->pNewObj = new OCustomShape(SERVICE_SHAPE);
                break;
            case OBJ_DLG_SUBREPORT:
                pObjFactory->pNewObj = new OOle2Obj(SERVICE_REPORTDEFINITION);
                break;
            case OBJ_OLE2:
                pObjFactory->pNewObj = new OOle2Obj(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.chart2.ChartDocument")));
                break;
            default:
                OSL_ENSURE(0,"Unknown object id");
                break;
        }
    }

    return 0;
}
//----------------------------------------------------------------------------
}
<commit_msg>INTEGRATION: CWS rptchart02 (1.3.4); FILE MERGED 2008/04/16 06:30:55 oj 1.3.4.2: RESYNC: (1.3-1.4); FILE MERGED 2008/03/12 09:45:18 oj 1.3.4.1: impl chart handling<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: dlgedfac.cxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#include "precompiled_reportdesign.hxx"
#include "dlgedfac.hxx"
#ifndef REPORTDESIGN_SHARED_UISTRINGS_HRC
#include "uistrings.hrc"
#endif
#include "RptObject.hxx"
#include <RptDef.hxx>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/awt/ScrollBarOrientation.hpp>
#include <svx/svdoole2.hxx>
namespace rptui
{
using namespace ::com::sun::star;

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

DlgEdFactory::DlgEdFactory()
{
    SdrObjFactory::InsertMakeObjectHdl( LINK(this, DlgEdFactory, MakeObject) );
}

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

DlgEdFactory::~DlgEdFactory()
{
    SdrObjFactory::RemoveMakeObjectHdl( LINK(this, DlgEdFactory, MakeObject) );
}

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

IMPL_LINK( DlgEdFactory, MakeObject, SdrObjFactory *, pObjFactory )
{
    if ( pObjFactory->nInventor == ReportInventor )
    {
        switch( pObjFactory->nIdentifier )
        {
            case OBJ_DLG_FIXEDTEXT:
                    pObjFactory->pNewObj = new OUnoObject( SERVICE_FIXEDTEXT
                                                        ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.form.component.FixedText"))
                                                        ,OBJ_DLG_FIXEDTEXT);
                    break;
            case OBJ_DLG_IMAGECONTROL:
                    pObjFactory->pNewObj = new OUnoObject( SERVICE_IMAGECONTROL
                                                        ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.form.component.DatabaseImageControl"))
                                                        ,OBJ_DLG_IMAGECONTROL);
                    break;
            case OBJ_DLG_FORMATTEDFIELD:
                    pObjFactory->pNewObj = new OUnoObject( SERVICE_FORMATTEDFIELD
                                                        ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.form.component.FormattedField"))
                                                        ,OBJ_DLG_FORMATTEDFIELD);
                    break;
            case OBJ_DLG_VFIXEDLINE:
            case OBJ_DLG_HFIXEDLINE:
                {
                    OUnoObject* pObj = new OUnoObject( SERVICE_FIXEDLINE
                                                        ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.UnoControlFixedLineModel"))
                                                        ,pObjFactory->nIdentifier);
                    pObjFactory->pNewObj = pObj;
                    if ( pObjFactory->nIdentifier == OBJ_DLG_HFIXEDLINE )
                    {
                        uno::Reference<beans::XPropertySet> xProp = pObj->getAwtComponent();
                        xProp->setPropertyValue( PROPERTY_ORIENTATION, uno::makeAny(sal_Int32(0)) );
                    }
                }
                break;
            case OBJ_CUSTOMSHAPE:
                pObjFactory->pNewObj = new OCustomShape(SERVICE_SHAPE);
                break;
            case OBJ_DLG_SUBREPORT:
                pObjFactory->pNewObj = new OOle2Obj(SERVICE_REPORTDEFINITION,OBJ_DLG_SUBREPORT);
                break;
            case OBJ_OLE2:
                pObjFactory->pNewObj = new OOle2Obj(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.chart2.ChartDocument")),OBJ_OLE2);
                break;
            default:
                OSL_ENSURE(0,"Unknown object id");
                break;
        }
    }

    return 0;
}
//----------------------------------------------------------------------------
}
<|endoftext|>