<commit_before>/*
 * This File is part of Davix, The IO library for HTTP based protocols
 * Copyright (C) CERN 2013
 * Author: Adrien Devresse <adrien.devresse@cern.ch>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
*/

#include "modules_profiles.hpp"
#include <sstream>

#include <davixcontext.hpp>
#include <utils/davix_logger_internal.hpp>
#include <system_utils/env_utils.hpp>

namespace Davix{

struct GridEnv{
    std::string cert_path;
    std::string key_path;
    std::string ca_path;
};

GridEnv createGridEnv(){

    DAVIX_SLOG(DAVIX_LOG_TRACE, DAVIX_LOG_CORE, "Enable GRID profile for DAVIX");

    GridEnv env;
    env.ca_path = EnvUtils::getEnv("X509_CERT_DIR", "/etc/grid-security/certificates/");
    DAVIX_SLOG(DAVIX_LOG_TRACE, DAVIX_LOG_CORE, "Add CA path {} to valid CA path list", env.ca_path);

    std::string proxy = EnvUtils::getEnv("X509_USER_PROXY", std::string());
    std::string key = EnvUtils::getEnv("X509_USER_KEY", std::string());
    std::string cert = EnvUtils::getEnv("X509_USER_CERT", std::string());

    std::string standard_location = fmt::format("/tmp/x509up_u{}", geteuid());

    if(!proxy.empty()) {
        DAVIX_SLOG(DAVIX_LOG_TRACE, DAVIX_LOG_CORE, "Using X509_USER_PROXY to supply credentials: {}", proxy);
        env.cert_path = env.key_path = proxy;
    }
    else if(!cert.empty()) {
        DAVIX_SLOG(DAVIX_LOG_TRACE, DAVIX_LOG_CORE, "Using X509_USER_CERT and X509_USER_KEY to supply credentials: {}, {}", cert, key);
        env.cert_path = cert;
        env.key_path = key;
        if(key.empty()) env.key_path = cert;
    }
    else if(access(standard_location.c_str(), R_OK) == 0) {
        DAVIX_SLOG(DAVIX_LOG_TRACE, DAVIX_LOG_CORE, "Using standard location for proxy: {}", standard_location);
        env.cert_path = env.key_path = standard_location;
    }
    else {
        DAVIX_SLOG(DAVIX_LOG_WARNING, DAVIX_LOG_CORE, "Unable to find a proxy or cert/key pair using either X509_USER_* variables or {}", standard_location);
    }

    return env;
}

void awesomeGridHook(RequestParams& p, HttpRequest & req, Uri & u, RequestPreRunHook previous_hook, GridEnv env_grid){

    // initialize environment
    // add grid CA path
    if(env_grid.ca_path.size() >0){
        p.addCertificateAuthorityPath(env_grid.ca_path);
    }
    // if no cert auth configured, configure one
    if(env_grid.cert_path.size() > 0){
        X509Credential x509;
        DavixError* tmp_err=NULL;
        if( x509.loadFromFilePEM(env_grid.key_path, env_grid.cert_path, "", &tmp_err) <0){
            DAVIX_SLOG(DAVIX_LOG_WARNING, DAVIX_LOG_CORE, "Impossible to load GRID certificate {} {}: {}",
                      env_grid.key_path,
                      env_grid.cert_path,
                      tmp_err->getErrMsg());

            if(tmp_err){
                std::cerr << "("<< tmp_err->getErrScope() <<") Error: "<< tmp_err->getErrMsg() << std::endl;
                DavixError::clearError(&tmp_err);
            }
        }else{
            // in current state, GRID profiles ignore all manually defined callbacks
            p.setClientCertCallbackX509(NULL, NULL);
            p.setClientCertX509(x509);
        }
    }

    if(previous_hook){
        previous_hook(p, req, u);
    }
}

void loadGridProfile(Context & context){
    GridEnv grid_env = createGridEnv();

    RequestPreRunHook previous_hook = context.getHook<RequestPreRunHook>();
    RequestPreRunHook new_hook = std::bind(awesomeGridHook, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, previous_hook, grid_env);
    context.setHook<RequestPreRunHook>(new_hook);
}

}
<commit_msg>Revert DMC-843<commit_after>/*
 * This File is part of Davix, The IO library for HTTP based protocols
 * Copyright (C) CERN 2013
 * Author: Adrien Devresse <adrien.devresse@cern.ch>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
*/

#include "modules_profiles.hpp"
#include <sstream>

#include <davixcontext.hpp>
#include <utils/davix_logger_internal.hpp>
#include <system_utils/env_utils.hpp>

namespace Davix{

struct GridEnv{
    std::string cert_path;
    std::string key_path;
    std::string ca_path;
};

GridEnv createGridEnv(){

    DAVIX_SLOG(DAVIX_LOG_TRACE, DAVIX_LOG_CORE, "Enable GRID profile for DAVIX");

    GridEnv env;
    env.ca_path = EnvUtils::getEnv("X509_CERT_DIR", "/etc/grid-security/certificates/");
    DAVIX_SLOG(DAVIX_LOG_TRACE, DAVIX_LOG_CORE, "Adding CA path {} to valid CA path list", env.ca_path);

    std::string proxy = EnvUtils::getEnv("X509_USER_PROXY", std::string());
    std::string key = EnvUtils::getEnv("X509_USER_KEY", std::string());
    std::string cert = EnvUtils::getEnv("X509_USER_CERT", std::string());

    std::string standard_location = fmt::format("/tmp/x509up_u{}", geteuid());

    if(!proxy.empty()) {
        DAVIX_SLOG(DAVIX_LOG_TRACE, DAVIX_LOG_CORE, "Using X509_USER_PROXY to supply credentials: {}", proxy);
        env.cert_path = env.key_path = proxy;
    }
    else if(access(standard_location.c_str(), R_OK) == 0) {
        DAVIX_SLOG(DAVIX_LOG_TRACE, DAVIX_LOG_CORE, "Using standard location for proxy: {}", standard_location);
        env.cert_path = env.key_path = standard_location;
    }
    else if(!cert.empty()) {
        DAVIX_SLOG(DAVIX_LOG_TRACE, DAVIX_LOG_CORE, "Using X509_USER_CERT and X509_USER_KEY to supply credentials: {}, {}", cert, key);
        env.cert_path = cert;
        env.key_path = key;
        if(key.empty()) env.key_path = cert;
    }
    else {
        DAVIX_SLOG(DAVIX_LOG_WARNING, DAVIX_LOG_CORE, "Unable to find a proxy or cert/key pair using either X509_USER_* variables or {}", standard_location);
    }

    return env;
}

void awesomeGridHook(RequestParams& p, HttpRequest & req, Uri & u, RequestPreRunHook previous_hook, GridEnv env_grid){

    // initialize environment
    // add grid CA path
    if(env_grid.ca_path.size() >0){
        p.addCertificateAuthorityPath(env_grid.ca_path);
    }
    // if no cert auth configured, configure one
    if(env_grid.cert_path.size() > 0){
        X509Credential x509;
        DavixError* tmp_err=NULL;
        if( x509.loadFromFilePEM(env_grid.key_path, env_grid.cert_path, "", &tmp_err) <0){
            DAVIX_SLOG(DAVIX_LOG_WARNING, DAVIX_LOG_CORE, "Impossible to load GRID certificate {} {}: {}",
                      env_grid.key_path,
                      env_grid.cert_path,
                      tmp_err->getErrMsg());

            if(tmp_err){
                std::cerr << "("<< tmp_err->getErrScope() <<") Error: "<< tmp_err->getErrMsg() << std::endl;
                DavixError::clearError(&tmp_err);
            }
        }else{
            // in current state, GRID profiles ignore all manually defined callbacks
            p.setClientCertCallbackX509(NULL, NULL);
            p.setClientCertX509(x509);
        }
    }

    if(previous_hook){
        previous_hook(p, req, u);
    }
}

void loadGridProfile(Context & context){
    GridEnv grid_env = createGridEnv();

    RequestPreRunHook previous_hook = context.getHook<RequestPreRunHook>();
    RequestPreRunHook new_hook = std::bind(awesomeGridHook, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, previous_hook, grid_env);
    context.setHook<RequestPreRunHook>(new_hook);
}

}
<|endoftext|>


<commit_before>// Standard includes
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <cmath>
#include <string.h>
#include <inttypes.h>
#include <fstream>
#include <limits.h>

// Serial includes
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#
#ifdef __linux
#include <sys/ioctl.h>
#endif

// include class definition
#include "wifly_serial.h"

// TODO: Investigate this parameter... what exactly does it do?
#define WD 1000

using std::string;
using namespace std;

WiflySerial::WiflySerial() : SerialPort() {
	printf("simple wifly constructor\n");
}

WiflySerial::WiflySerial(bool verbose) : SerialPort(verbose) {
	// nothing specific to do in this constructor
	printf("verbose wifly constructor\n");
}

WiflySerial::WiflySerial(bool verbose, char* &uart_name) : SerialPort(verbose, uart_name) {
	printf("complex wifly constructor\n");
}

WiflySerial::~WiflySerial() {
	// nothing to do in the destructor
}

void WiflySerial::enter_commandmode() {

	if (_verbose) printf("entering command mode...\n");

	// First, we must make sure we are in command mode
	// For now, let's assume we just booted up
	/*
	write(fd, "exit\r", 5);
	usleep(WD);
	write(fd, "exit\r", 5);
	usleep(WD);
	*/

	/* Give it the turn on command */
	/* Must wait 250 ms before and after giving $$$ command */
	/* To be safe, I wait 300 ms */
	write(fd, "$$$", 3);
	usleep(300000);
}

/**
 * Scans the channels and returns the rssi of the specified SSID
 */
int WiflySerial::scanrssi(char *ssid) {
	if (_verbose) printf("scanning...\n");
	char buf[2048];
	write(fd, "scan 10\r", 8);
	usleep(1000000);
	if (_verbose) printf("reading from wifly...\n");

	read(fd, buf, sizeof(buf));
	if (_verbose) printf("%s\n", buf);

	return parserssi(buf, ssid);
}

// temporary function TO BE DELTED
int WiflySerial::scanrssi2(char *ssid) {
	if (_verbose) printf("scanning in 2...\n");
	char buf[20480];
	write(fd, "scan 10\r", 8);
	usleep(1000000);
	if (_verbose) printf("reading from wifly...\n");

	read(fd, buf, sizeof(buf));
	if (_verbose) printf("%s\n", buf);

	/*
	while (read(fd, buf, sizeof(buf)) > 0) {
		if (_verbose) printf("%s\n", buf);
		//if (rssi == INT_MAX) {
		//	rssi = getrssi(buf, ssid);
		//}
	}
	*/
	return parserssi(buf, ssid);
	//return rssi;
}

/**
 * Scans numtimes times and prints rssi values to a line in a file
 */
int WiflySerial::scanrssi_f(char *ssid, FILE *f, int numtimes)
{
	numtimes = 1;
	if (_verbose) printf("scanning to write to file...\n");
	int rssi_value, i;
	for (i = 1; i <= (numtimes-1); i++)
	{
		rssi_value = scanrssi(ssid);
		fprintf(f, "%i,", rssi_value);
		//printf("rssi_value = %i\n", rssi_value);
	}

	/* Don't include comma for last one */
	rssi_value = scanrssi(ssid);
	fprintf(f, "%i\n", rssi_value);
	//printf("rssi_value = %i\n", rssi_value);

	return rssi_value;
}

// private functions

/**
 * Parses output from scan command.
 * Searches for SSID provided.
 * Returns the RSSI value of that SSID, as an int.
 */
int WiflySerial::getrssi(char *buf, char *ssid)
{
	if (_verbose) printf("getting rssi from message...\n");

	char *delim = (char *) "\n";
	char *token = strtok(buf, delim);
	int rssi_value = INT_MAX;

	//if (_verbose) printf("%s\n", buf);

	if (_verbose) printf("starting get while loop...\n");
	while (token)
	{
		if (_verbose) printf("%s\n", token);

		if (strstr(token, ssid) != NULL)
		{
			char *comma_delim = (char *)  ",";
			char *jam_token = strtok(token, comma_delim);
			jam_token =	strtok(0, comma_delim);
			jam_token =	strtok(0, comma_delim);
			rssi_value = atoi(jam_token);
			token = NULL;
		}
		else
		{
			token = strtok(0, delim);
		}
	}

	return rssi_value;
}

/*
 * New function for parsing message, ideally prevents seg faults
 */
int WiflySerial::parserssi(char* buf, char* ssid) {
	if (_verbose) printf("parsing rssi from message...\n");

	char *delim = (char *) "\n";
	char *comma_delim = (char *)  ",";
	char *jam_token;
	char *pEnd;
	int i = 0;
	int rssi_value = INT_MAX;

	char *token = strtok(buf, delim);

	// get to the starting point of the message
	while (token != NULL && strstr(token, (char*) "SCAN:Found") == NULL) {
		token = strtok(NULL, delim);
	}

	// can get the information of how many entries found
	//jam_token = strtok(token, " ");
	//jam_token = strtok(NULL, " ");
	//if (_verbose) printf("found %s results\n", jam_token);

	// get to the first actual line of the scan results
	token = strtok(NULL, delim);

	// now loop through to the end of the message
	while (token != NULL && strstr(token, (char*) "END:") == NULL) {

		if (_verbose) printf("%s\n", token);

		// check to see if this row contains the desired SSID
		if (strstr(token, ssid) != NULL) {
			jam_token = strtok(token, comma_delim);

			while (jam_token != NULL && i < 2) {
				jam_token = strtok(NULL, comma_delim);
				i++;
			}
			i = 0;

			// jam_token should now contain the rssi value
			// need to make sure it's not null and is an int
			if (jam_token != NULL) {
				rssi_value = (int) strtol(jam_token, &pEnd, 10);

				printf("rssi value parsed: %i\n", rssi_value);

				// check to make sure this was indeed the rssi value
				if (strstr(pEnd, "\0") == NULL) {
					printf("rssi not correct value\n");
					rssi_value = INT_MAX;
				}
			}

			// set token to null to end search
			token = NULL;
		} else {
			// get the next line
			token = strtok(NULL, delim);
		}
	}

	// return the rssi value
	return rssi_value;
}

<commit_msg>remove unused functions and change sleep after command to 0.5 sec<commit_after>// Standard includes
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <cmath>
#include <string.h>
#include <inttypes.h>
#include <fstream>
#include <limits.h>

// Serial includes
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#
#ifdef __linux
#include <sys/ioctl.h>
#endif

// include class definition
#include "wifly_serial.h"

// TODO: Investigate this parameter... what exactly does it do?
#define WD 1000

using std::string;
using namespace std;

WiflySerial::WiflySerial() : SerialPort() {
	printf("simple wifly constructor\n");
}

WiflySerial::WiflySerial(bool verbose) : SerialPort(verbose) {
	// nothing specific to do in this constructor
	printf("verbose wifly constructor\n");
}

WiflySerial::WiflySerial(bool verbose, char* &uart_name) : SerialPort(verbose, uart_name) {
	printf("complex wifly constructor\n");
}

WiflySerial::~WiflySerial() {
	// nothing to do in the destructor
}

void WiflySerial::enter_commandmode() {

	if (_verbose) printf("entering command mode...\n");

	// First, we must make sure we are in command mode
	// For now, let's assume we just booted up
	/*
	write(fd, "exit\r", 5);
	usleep(WD);
	write(fd, "exit\r", 5);
	usleep(WD);
	*/

	/* Give it the turn on command */
	/* Must wait 250 ms before and after giving $$$ command */
	/* To be safe, I wait 300 ms */
	write(fd, "$$$", 3);
	usleep(300000);
}

/**
 * Scans the channels and returns the rssi of the specified SSID
 */
int WiflySerial::scanrssi(char *ssid) {
	if (_verbose) printf("scanning...\n");
	char buf[2048];
	write(fd, "scan 10\r", 8);
	usleep(500000);
	if (_verbose) printf("reading from wifly...\n");

	read(fd, buf, sizeof(buf));
	if (_verbose) printf("%s\n", buf);

	return parserssi(buf, ssid);
}

// private functions

/*
 * New function for parsing message, ideally prevents seg faults
 */
int WiflySerial::parserssi(char* buf, char* ssid) {
	if (_verbose) printf("parsing rssi from message...\n");

	char *delim = (char *) "\n";
	char *comma_delim = (char *)  ",";
	char *jam_token;
	char *pEnd;
	int i = 0;
	int rssi_value = INT_MAX;

	char *token = strtok(buf, delim);

	// get to the starting point of the message
	while (token != NULL && strstr(token, (char*) "SCAN:Found") == NULL) {
		token = strtok(NULL, delim);
	}

	// can get the information of how many entries found
	//jam_token = strtok(token, " ");
	//jam_token = strtok(NULL, " ");
	//if (_verbose) printf("found %s results\n", jam_token);

	// get to the first actual line of the scan results
	token = strtok(NULL, delim);

	// now loop through to the end of the message
	while (token != NULL && strstr(token, (char*) "END:") == NULL) {

		if (_verbose) printf("%s\n", token);

		// check to see if this row contains the desired SSID
		if (strstr(token, ssid) != NULL) {
			jam_token = strtok(token, comma_delim);

			while (jam_token != NULL && i < 2) {
				jam_token = strtok(NULL, comma_delim);
				i++;
			}
			i = 0;

			// jam_token should now contain the rssi value
			// need to make sure it's not null and is an int
			if (jam_token != NULL) {
				rssi_value = (int) strtol(jam_token, &pEnd, 10);

				printf("rssi value parsed: %i\n", rssi_value);

				// check to make sure this was indeed the rssi value
				if (strstr(pEnd, "\0") == NULL) {
					printf("rssi not correct value\n");
					rssi_value = INT_MAX;
				}
			}

			// set token to null to end search
			token = NULL;
		} else {
			// get the next line
			token = strtok(NULL, delim);
		}
	}

	// return the rssi value
	return rssi_value;
}

<|endoftext|>


<commit_before><commit_msg>Don't make use of cvtps2dq in MSan builds<commit_after><|endoftext|>


<commit_before>//===- LowerAllocations.cpp - Reduce malloc & free insts to calls ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The LowerAllocations transformation is a target-dependent tranformation
// because it depends on the size of data types and alignment constraints.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "lowerallocs"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Constants.h"
#include "llvm/Pass.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Support/Compiler.h"
using namespace llvm;

STATISTIC(NumLowered, "Number of allocations lowered");

namespace {
  /// LowerAllocations - Turn malloc and free instructions into %malloc and
  /// %free calls.
  ///
  class VISIBILITY_HIDDEN LowerAllocations : public BasicBlockPass {
    Constant *MallocFunc;   // Functions in the module we are processing
    Constant *FreeFunc;     // Initialized by doInitialization
    bool LowerMallocArgToInteger;
  public:
    static char ID; // Pass ID, replacement for typeid
    explicit LowerAllocations(bool LowerToInt = false)
      : BasicBlockPass(&ID), MallocFunc(0), FreeFunc(0),
        LowerMallocArgToInteger(LowerToInt) {}

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<TargetData>();
      AU.setPreservesCFG();

      // This is a cluster of orthogonal Transforms:
      AU.addPreserved<UnifyFunctionExitNodes>();
      AU.addPreservedID(PromoteMemoryToRegisterID);
      AU.addPreservedID(LowerSwitchID);
      AU.addPreservedID(LowerInvokePassID);
    }

    /// doPassInitialization - For the lower allocations pass, this ensures that
    /// a module contains a declaration for a malloc and a free function.
    ///
    bool doInitialization(Module &M);

    virtual bool doInitialization(Function &F) {
      return BasicBlockPass::doInitialization(F);
    }

    /// runOnBasicBlock - This method does the actual work of converting
    /// instructions over, assuming that the pass has already been initialized.
    ///
    bool runOnBasicBlock(BasicBlock &BB);
  };
}

char LowerAllocations::ID = 0;
static RegisterPass<LowerAllocations>
X("lowerallocs", "Lower allocations from instructions to calls");

// Publically exposed interface to pass...
const PassInfo *const llvm::LowerAllocationsID = &X;
// createLowerAllocationsPass - Interface to this file...
Pass *llvm::createLowerAllocationsPass(bool LowerMallocArgToInteger) {
  return new LowerAllocations(LowerMallocArgToInteger);
}

// doInitialization - For the lower allocations pass, this ensures that a
// module contains a declaration for a malloc and a free function.
//
// This function is always successful.
//
bool LowerAllocations::doInitialization(Module &M) {
  const Type *BPTy = PointerType::getUnqual(Type::Int8Ty);
  // Prototype malloc as "char* malloc(...)", because we don't know in
  // doInitialization whether size_t is int or long.
  FunctionType *FT = FunctionType::get(BPTy, std::vector<const Type*>(), true);
  MallocFunc = M.getOrInsertFunction("malloc", FT);
  FreeFunc = M.getOrInsertFunction("free"  , Type::VoidTy, BPTy, (Type *)0);
  return true;
}

// runOnBasicBlock - This method does the actual work of converting
// instructions over, assuming that the pass has already been initialized.
//
bool LowerAllocations::runOnBasicBlock(BasicBlock &BB) {
  bool Changed = false;
  assert(MallocFunc && FreeFunc && "Pass not initialized!");

  BasicBlock::InstListType &BBIL = BB.getInstList();

  const TargetData &TD = getAnalysis<TargetData>();
  const Type *IntPtrTy = TD.getIntPtrType();

  // Loop over all of the instructions, looking for malloc or free instructions
  for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) {
    if (MallocInst *MI = dyn_cast<MallocInst>(I)) {
      const Type *AllocTy = MI->getType()->getElementType();

      // malloc(type) becomes sbyte *malloc(size)
      Value *MallocArg;
      if (LowerMallocArgToInteger)
        MallocArg = ConstantInt::get(Type::Int64Ty, TD.getABITypeSize(AllocTy));
      else
        MallocArg = ConstantExpr::getSizeOf(AllocTy);
      MallocArg = ConstantExpr::getTruncOrBitCast(cast<Constant>(MallocArg),
                                                  IntPtrTy);

      if (MI->isArrayAllocation()) {
        if (isa<ConstantInt>(MallocArg) &&
            cast<ConstantInt>(MallocArg)->isOne()) {
          MallocArg = MI->getOperand(0);         // Operand * 1 = Operand
        } else if (Constant *CO = dyn_cast<Constant>(MI->getOperand(0))) {
          CO = ConstantExpr::getIntegerCast(CO, IntPtrTy, false /*ZExt*/);
          MallocArg = ConstantExpr::getMul(CO, cast<Constant>(MallocArg));
        } else {
          Value *Scale = MI->getOperand(0);
          if (Scale->getType() != IntPtrTy)
            Scale = CastInst::CreateIntegerCast(Scale, IntPtrTy, false /*ZExt*/,
                                                "", I);

          // Multiply it by the array size if necessary...
          MallocArg = BinaryOperator::Create(Instruction::Mul, Scale,
                                             MallocArg, "", I);
        }
      }

      // Create the call to Malloc.
      CallInst *MCall = CallInst::Create(MallocFunc, MallocArg, "", I);
      MCall->setTailCall();

      // Create a cast instruction to convert to the right type...
      Value *MCast;
      if (MCall->getType() != Type::VoidTy)
        MCast = new BitCastInst(MCall, MI->getType(), "", I);
      else
        MCast = Constant::getNullValue(MI->getType());

      // Replace all uses of the old malloc inst with the cast inst
      MI->replaceAllUsesWith(MCast);
      I = --BBIL.erase(I);         // remove and delete the malloc instr...
      Changed = true;
      ++NumLowered;
    } else if (FreeInst *FI = dyn_cast<FreeInst>(I)) {
      Value *PtrCast =
        new BitCastInst(FI->getOperand(0),
                        PointerType::getUnqual(Type::Int8Ty), "", I);

      // Insert a call to the free function...
      CallInst::Create(FreeFunc, PtrCast, "", I)->setTailCall();

      // Delete the old free instruction
      I = --BBIL.erase(I);
      Changed = true;
      ++NumLowered;
    }
  }

  return Changed;
}

<commit_msg>Initialize MallocFunc and FreeFunc properly.<commit_after>//===- LowerAllocations.cpp - Reduce malloc & free insts to calls ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The LowerAllocations transformation is a target-dependent tranformation
// because it depends on the size of data types and alignment constraints.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "lowerallocs"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Constants.h"
#include "llvm/Pass.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Support/Compiler.h"
using namespace llvm;

STATISTIC(NumLowered, "Number of allocations lowered");

namespace {
  /// LowerAllocations - Turn malloc and free instructions into %malloc and
  /// %free calls.
  ///
  class VISIBILITY_HIDDEN LowerAllocations : public BasicBlockPass {
    Constant *MallocFunc;   // Functions in the module we are processing
    Constant *FreeFunc;     // Initialized by doInitialization
    bool LowerMallocArgToInteger;
  public:
    static char ID; // Pass ID, replacement for typeid
    explicit LowerAllocations(bool LowerToInt = false)
      : BasicBlockPass(&ID), MallocFunc(0), FreeFunc(0),
        LowerMallocArgToInteger(LowerToInt) {}

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<TargetData>();
      AU.setPreservesCFG();

      // This is a cluster of orthogonal Transforms:
      AU.addPreserved<UnifyFunctionExitNodes>();
      AU.addPreservedID(PromoteMemoryToRegisterID);
      AU.addPreservedID(LowerSwitchID);
      AU.addPreservedID(LowerInvokePassID);
    }

    /// doPassInitialization - For the lower allocations pass, this ensures that
    /// a module contains a declaration for a malloc and a free function.
    ///
    bool doInitialization(Module &M);

    virtual bool doInitialization(Function &F) {
      return doInitialization(*F.getParent());
    }

    /// runOnBasicBlock - This method does the actual work of converting
    /// instructions over, assuming that the pass has already been initialized.
    ///
    bool runOnBasicBlock(BasicBlock &BB);
  };
}

char LowerAllocations::ID = 0;
static RegisterPass<LowerAllocations>
X("lowerallocs", "Lower allocations from instructions to calls");

// Publically exposed interface to pass...
const PassInfo *const llvm::LowerAllocationsID = &X;
// createLowerAllocationsPass - Interface to this file...
Pass *llvm::createLowerAllocationsPass(bool LowerMallocArgToInteger) {
  return new LowerAllocations(LowerMallocArgToInteger);
}

// doInitialization - For the lower allocations pass, this ensures that a
// module contains a declaration for a malloc and a free function.
//
// This function is always successful.
//
bool LowerAllocations::doInitialization(Module &M) {
  const Type *BPTy = PointerType::getUnqual(Type::Int8Ty);
  // Prototype malloc as "char* malloc(...)", because we don't know in
  // doInitialization whether size_t is int or long.
  FunctionType *FT = FunctionType::get(BPTy, std::vector<const Type*>(), true);
  MallocFunc = M.getOrInsertFunction("malloc", FT);
  FreeFunc = M.getOrInsertFunction("free"  , Type::VoidTy, BPTy, (Type *)0);
  return true;
}

// runOnBasicBlock - This method does the actual work of converting
// instructions over, assuming that the pass has already been initialized.
//
bool LowerAllocations::runOnBasicBlock(BasicBlock &BB) {
  bool Changed = false;
  assert(MallocFunc && FreeFunc && "Pass not initialized!");

  BasicBlock::InstListType &BBIL = BB.getInstList();

  const TargetData &TD = getAnalysis<TargetData>();
  const Type *IntPtrTy = TD.getIntPtrType();

  // Loop over all of the instructions, looking for malloc or free instructions
  for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) {
    if (MallocInst *MI = dyn_cast<MallocInst>(I)) {
      const Type *AllocTy = MI->getType()->getElementType();

      // malloc(type) becomes sbyte *malloc(size)
      Value *MallocArg;
      if (LowerMallocArgToInteger)
        MallocArg = ConstantInt::get(Type::Int64Ty, TD.getABITypeSize(AllocTy));
      else
        MallocArg = ConstantExpr::getSizeOf(AllocTy);
      MallocArg = ConstantExpr::getTruncOrBitCast(cast<Constant>(MallocArg),
                                                  IntPtrTy);

      if (MI->isArrayAllocation()) {
        if (isa<ConstantInt>(MallocArg) &&
            cast<ConstantInt>(MallocArg)->isOne()) {
          MallocArg = MI->getOperand(0);         // Operand * 1 = Operand
        } else if (Constant *CO = dyn_cast<Constant>(MI->getOperand(0))) {
          CO = ConstantExpr::getIntegerCast(CO, IntPtrTy, false /*ZExt*/);
          MallocArg = ConstantExpr::getMul(CO, cast<Constant>(MallocArg));
        } else {
          Value *Scale = MI->getOperand(0);
          if (Scale->getType() != IntPtrTy)
            Scale = CastInst::CreateIntegerCast(Scale, IntPtrTy, false /*ZExt*/,
                                                "", I);

          // Multiply it by the array size if necessary...
          MallocArg = BinaryOperator::Create(Instruction::Mul, Scale,
                                             MallocArg, "", I);
        }
      }

      // Create the call to Malloc.
      CallInst *MCall = CallInst::Create(MallocFunc, MallocArg, "", I);
      MCall->setTailCall();

      // Create a cast instruction to convert to the right type...
      Value *MCast;
      if (MCall->getType() != Type::VoidTy)
        MCast = new BitCastInst(MCall, MI->getType(), "", I);
      else
        MCast = Constant::getNullValue(MI->getType());

      // Replace all uses of the old malloc inst with the cast inst
      MI->replaceAllUsesWith(MCast);
      I = --BBIL.erase(I);         // remove and delete the malloc instr...
      Changed = true;
      ++NumLowered;
    } else if (FreeInst *FI = dyn_cast<FreeInst>(I)) {
      Value *PtrCast =
        new BitCastInst(FI->getOperand(0),
                        PointerType::getUnqual(Type::Int8Ty), "", I);

      // Insert a call to the free function...
      CallInst::Create(FreeFunc, PtrCast, "", I)->setTailCall();

      // Delete the old free instruction
      I = --BBIL.erase(I);
      Changed = true;
      ++NumLowered;
    }
  }

  return Changed;
}

<|endoftext|>


<commit_before><commit_msg>fixed Déjà-vu<commit_after><|endoftext|>


<commit_before><commit_msg>Vga terminal now moves cursor around<commit_after><|endoftext|>


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

#ifndef xeumeuleu_null_input_hpp
#define xeumeuleu_null_input_hpp

#include <xeumeuleu/streams/exception.hpp>
#include <xeumeuleu/streams/detail/input_base.hpp>
#include <xeumeuleu/streams/detail/input_context.hpp>

namespace xml
{
// =============================================================================
/** @class  null_input
    @brief  Null input implementation
*/
// Created: MAT 2006-01-08
// =============================================================================
class null_input : public input_base
{
public:
    //! @name Constructors/Destructor
    //@{
    explicit null_input( const input_base& input )
        : context_( input.context() )
        , level_( 0 )
    {}
    null_input( const null_input& input )
        : context_( input.context() )
        , level_( 0 )
    {}
    virtual ~null_input()
    {}
    //@}

    //! @name Operations
    //@{
    virtual void start( const std::string& /*tag*/ )
    {
        ++level_;
    }
    virtual void end()
    {
        if( --level_ < 0 )
            throw xml::exception( "Invalid 'end' at root level" );
    }

    virtual void read( std::string& /*value*/ ) const {}
    virtual void read( bool& /*value*/ ) const {}
    virtual void read( short& /*value*/ ) const {}
    virtual void read( int& /*value*/ ) const {}
    virtual void read( long& /*value*/ ) const {}
    virtual void read( long long& /*value*/ ) const {}
    virtual void read( float& /*value*/ ) const {}
    virtual void read( double& /*value*/ ) const {}
    virtual void read( long double& /*value*/ ) const {}
    virtual void read( unsigned short& /*value*/ ) const {}
    virtual void read( unsigned int& /*value*/ ) const {}
    virtual void read( unsigned long& /*value*/ ) const {}
    virtual void read( unsigned long long& /*value*/ ) const {}

    virtual std::auto_ptr< input_base > branch( bool /*clone*/ ) const
    {
        return std::auto_ptr< input_base >( new null_input( *this ) );
    }

    virtual void copy( output& /*destination*/ ) const
    {}
    //@}

    //! @name Accessors
    //@{
    virtual bool has_child( const std::string& /*name*/ ) const
    {
        return false;
    }
    virtual bool has_attribute( const std::string& /*name*/ ) const
    {
        return false;
    }
    virtual bool has_content() const
    {
        return false;
    }

    virtual void attribute( const std::string& /*name*/, std::string& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, bool& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, short& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, int& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, long& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, long long& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, float& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, double& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, long double& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, unsigned short& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, unsigned int& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, unsigned long& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, unsigned long long& /*value*/ ) const {}

    virtual void nodes( const visitor& /*v*/ ) const
    {}
    virtual void attributes( const visitor& /*v*/ ) const
    {}

    virtual std::string context() const
    {
        return context_;
    }
    //@}

private:
    //! @name Member data
    //@{
    const std::string context_;
    int level_;
    //@}
};

}

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

#ifndef xeumeuleu_null_input_hpp
#define xeumeuleu_null_input_hpp

#include <xeumeuleu/streams/exception.hpp>
#include <xeumeuleu/streams/detail/input_base.hpp>
#include <xeumeuleu/streams/detail/input_context.hpp>

namespace xml
{
// =============================================================================
/** @class  null_input
    @brief  Null input implementation
*/
// Created: MAT 2006-01-08
// =============================================================================
class null_input : public input_base
{
public:
    //! @name Constructors/Destructor
    //@{
    explicit null_input( const input_base& input )
        : context_( input.context() )
        , level_( 0 )
    {}
    null_input( const null_input& input )
        : input_base()
        , context_( input.context() )
        , level_( 0 )
    {}
    virtual ~null_input()
    {}
    //@}

    //! @name Operations
    //@{
    virtual void start( const std::string& /*tag*/ )
    {
        ++level_;
    }
    virtual void end()
    {
        if( --level_ < 0 )
            throw xml::exception( "Invalid 'end' at root level" );
    }

    virtual void read( std::string& /*value*/ ) const {}
    virtual void read( bool& /*value*/ ) const {}
    virtual void read( short& /*value*/ ) const {}
    virtual void read( int& /*value*/ ) const {}
    virtual void read( long& /*value*/ ) const {}
    virtual void read( long long& /*value*/ ) const {}
    virtual void read( float& /*value*/ ) const {}
    virtual void read( double& /*value*/ ) const {}
    virtual void read( long double& /*value*/ ) const {}
    virtual void read( unsigned short& /*value*/ ) const {}
    virtual void read( unsigned int& /*value*/ ) const {}
    virtual void read( unsigned long& /*value*/ ) const {}
    virtual void read( unsigned long long& /*value*/ ) const {}

    virtual std::auto_ptr< input_base > branch( bool /*clone*/ ) const
    {
        return std::auto_ptr< input_base >( new null_input( *this ) );
    }

    virtual void copy( output& /*destination*/ ) const
    {}
    //@}

    //! @name Accessors
    //@{
    virtual bool has_child( const std::string& /*name*/ ) const
    {
        return false;
    }
    virtual bool has_attribute( const std::string& /*name*/ ) const
    {
        return false;
    }
    virtual bool has_content() const
    {
        return false;
    }

    virtual void attribute( const std::string& /*name*/, std::string& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, bool& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, short& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, int& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, long& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, long long& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, float& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, double& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, long double& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, unsigned short& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, unsigned int& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, unsigned long& /*value*/ ) const {}
    virtual void attribute( const std::string& /*name*/, unsigned long long& /*value*/ ) const {}

    virtual void nodes( const visitor& /*v*/ ) const
    {}
    virtual void attributes( const visitor& /*v*/ ) const
    {}

    virtual std::string context() const
    {
        return context_;
    }
    //@}

private:
    //! @name Member data
    //@{
    const std::string context_;
    int level_;
    //@}
};

}

#endif // xeumeuleu_null_input_hpp
<|endoftext|>


<commit_before><commit_msg>shmrenderer: reset frame when shm stops<commit_after><|endoftext|>


<commit_before>/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Tabbed container.
*/

#pragma once

#include <Onsang/config.hpp>
#include <Onsang/aux.hpp>
#include <Onsang/utility.hpp>
#include <Onsang/UI/Defs.hpp>

#include <Beard/ui/Widget/Base.hpp>
#include <Beard/ui/Root.hpp>

namespace Onsang {
namespace UI {

// Forward declarations
class TabbedContainer;

/**
	Prototype slot-based container widget.
*/
class TabbedContainer
	: public UI::Widget::Base
{
public:
	using SPtr = aux::shared_ptr<UI::TabbedContainer>;

private:
	using base = UI::Widget::Base;
	enum class ctor_priv {};

	struct Tab {
		String title;
		UI::Widget::SPtr widget;
	};

	unsigned m_position;
	aux::vector<Tab> m_tabs;

	TabbedContainer() noexcept = delete;
	TabbedContainer(TabbedContainer const&) = delete;
	TabbedContainer& operator=(TabbedContainer const&) = delete;

	void push_back(UI::Widget::SPtr /*widget*/) {}

protected:
// Beard::ui::Widget::Base implementation
	void
	cache_geometry_impl() noexcept override {
		auto rs = get_geometry().get_request_size();
		if (!m_tabs.empty()) {
			Tab const& tab = m_tabs.at(m_position);
			if (tab.widget) {
				tab.widget->cache_geometry();
				auto const& ws = tab.widget->get_geometry().get_request_size();
				rs.width  = max_ce(rs.width , ws.width);
				rs.height = max_ce(rs.height, ws.height);
			}
		}
		if (!get_geometry().is_static()) {
			get_geometry().set_request_size(std::move(rs));
		}
	}

	void
	reflow_impl(
		Rect const& area,
		bool const cache
	) noexcept override {
		base::reflow_impl(area, cache);
		if (m_tabs.empty()) {
			return;
		}
		Rect child_frame = area;
		++child_frame.pos.y;
		--child_frame.size.height;
		vec2_clamp_min(child_frame.size, Vec2{0, 0});
		unsigned index = 0;
		for (auto& tab : m_tabs) {
			if (index == m_position) {
				tab.widget->reflow(child_frame, false);
			}
			++index;
		}
	}

	void
	render_impl(
		UI::Widget::RenderData& rd
	) noexcept override {
		if (m_tabs.empty()) {
			 return;
		}
		auto const& frame = get_geometry().get_frame();
		unsigned index = 0;
		signed xpos = 0;
		for (auto& tab : m_tabs) {
			bool const active = index == m_position;
			rd.terminal.put_sequence(
				frame.pos.x + xpos,
				frame.pos.y,
				Beard::txt::Sequence{tab.title, 0u, tab.title.size()},
				unsigned_cast(max_ce(0, frame.size.width)),
				rd.get_attr(active
					? ui::property_content_fg_selected
					: ui::property_content_fg_inactive
				),
				rd.get_attr(active
					? ui::property_content_bg_selected
					: ui::property_content_bg_inactive
				)
			);
			if (active) {
				tab.widget->render(rd);
			}
			if (index + 1 != m_tabs.size()) {
				xpos += tab.title.size() + 1;
				rd.terminal.put_cell(
					frame.pos.x + xpos,
					frame.pos.y,
					Beard::tty::make_cell(
						U'│',
						Beard::tty::Attr::bold |
						Beard::tty::Color::blue,
						Beard::tty::Color::term_default
					)
				);
				xpos += 2;
			}
			++index;
		}
	}

	signed
	num_children_impl() const noexcept override {
		return static_cast<signed>(m_tabs.size());
	}

	UI::Widget::SPtr
	get_child_impl(
		signed const index
	) override {
		return m_tabs.at(static_cast<unsigned>(index)).widget;
	}

public:
// special member functions
	~TabbedContainer() noexcept override = default;

	TabbedContainer(
		ctor_priv const,
		UI::RootWPtr&& root,
		UI::Widget::WPtr&& parent
	) noexcept
		: base(
			static_cast<UI::Widget::Type>(UI::OnsangWidgetType::TabbedContainer),
			enum_combine(
				UI::Widget::Flags::trait_container,
				UI::Widget::Flags::visible
			),
			UI::group_null,
			{{0, 0}, true, UI::Axis::both, UI::Axis::both},
			std::move(root),
			std::move(parent)
		)
		, m_position(0)
		, m_tabs()
	{}

	TabbedContainer(TabbedContainer&&) = default;
	TabbedContainer& operator=(TabbedContainer&&) = default;

	static UI::TabbedContainer::SPtr
	make(
		UI::RootWPtr root,
		UI::Widget::WPtr parent = UI::Widget::WPtr()
	) {
		return aux::make_shared<UI::TabbedContainer>(
			ctor_priv{},
			std::move(root),
			std::move(parent)
		);
	}

// properties
	bool
	empty() const noexcept {
		return m_tabs.empty();
	}

	unsigned
	get_tab() const noexcept {
		return m_position;
	}

	unsigned
	get_last_index() const noexcept {
		return m_tabs.empty()
			? 0
			: static_cast<unsigned>(m_tabs.size() - 1)
		;
	}

// operations
	void
	push_back(
		String title,
		UI::Widget::SPtr&& widget
	) {
		insert(std::move(title), std::move(widget), m_tabs.size());
		set_current_tab(get_last_index());
	}

	void
	insert(
		String title,
		UI::Widget::SPtr widget,
		unsigned index
	) {
		index = min_ce(index, static_cast<unsigned>(m_tabs.size()));
		widget->set_parent(shared_from_this(), index);
		if (m_tabs.empty()) {
			m_position = 0;
			widget->set_visible(true);
		} else if (index <= m_position) {
			++m_position;
			widget->set_visible(false);
		}
		m_tabs.insert(
			m_tabs.cbegin() + index,
			Tab{std::move(title), std::move(widget)}
		);
		for (; m_tabs.size() > index; ++index) {
			m_tabs[index].widget->set_index(static_cast<UI::index_type>(index));
		}
		queue_actions(enum_combine(
			UI::UpdateActions::reflow,
			UI::UpdateActions::render
		));
	}

	void
	remove(
		unsigned index
	) {
		m_tabs.erase(m_tabs.cbegin() + index);
		m_position = min_ce(m_position, get_last_index());
		for (; m_tabs.size() > index; ++index) {
			m_tabs[index].widget->set_index(static_cast<UI::index_type>(index));
		}
		if (!m_tabs.empty()) {
			m_tabs[m_position].widget->set_visible(true);
		}
		queue_actions(enum_combine(
			UI::UpdateActions::reflow,
			UI::UpdateActions::render
		));
	}

	void
	remove_current() {
		if (!m_tabs.empty()) {
			get_root()->clear_focus();
			remove(m_position);
		}
	}

	void
	clear() {
		m_tabs.clear();
		m_position = 0;
		queue_actions(enum_combine(
			UI::UpdateActions::reflow,
			UI::UpdateActions::render
		));
	}

	void
	set_title(
		unsigned const index,
		String title
	) {
		m_tabs.at(index).title = std::move(title);
		queue_actions(enum_combine(
			UI::UpdateActions::reflow,
			UI::UpdateActions::render
		));
	}

	void
	set_tab(
		std::size_t const index,
		UI::Widget::SPtr widget
	) {
		m_tabs.at(index).widget = std::move(widget);
	}

	void
	set_current_tab(
		unsigned index
	) {
		index = min_ce(index, get_last_index());
		if (!m_tabs.empty() && index != m_position) {
			// TODO: Track focused widget per-tab
			get_root()->clear_focus();
			m_tabs[m_position].widget->set_visible(false);
			m_tabs[index].widget->set_visible(true);
			m_position = index;
			queue_actions(enum_combine(
				UI::UpdateActions::reflow,
				UI::UpdateActions::render
			));
		}
	}

	void
	prev_tab() {
		if (0 < m_position) {
			set_current_tab(m_position - 1);
		}
	}

	void
	next_tab() {
		set_current_tab(m_position + 1);
	}

	void
	move_tab(
		unsigned from,
		unsigned to,
		bool const insert = false
	) {
		from = min_ce(from, get_last_index());
		to = min_ce(to, get_last_index());
		if (from != to) {
			if (insert) {
				Tab tab = m_tabs[from];
				m_tabs.erase(m_tabs.cbegin() + from);
				m_tabs.insert(m_tabs.cbegin() + to, std::move(tab));
				for (
					unsigned index = min_ce(from, to);
					m_tabs.size() > index;
					++index
				) {
					m_tabs[index].widget->set_index(static_cast<UI::index_type>(index));
				}
			} else {
				m_tabs[from].widget->set_index(to);
				m_tabs[to].widget->set_index(from);
				std::swap(m_tabs[from], m_tabs[to]);
			}
			if (from == m_position) {
				m_position = to;
			}
			queue_actions(enum_combine(
				UI::UpdateActions::flag_noclear,
				UI::UpdateActions::render
			));
		}
	}

	void
	move_left(
		unsigned const index,
		bool const insert = false
	) {
		if (index > 0) {
			move_tab(index, index - 1, insert);
		}
	}

	void
	move_right(
		unsigned const index,
		bool const insert = false
	) {
		move_tab(index, index + 1, insert);
	}
};

} // namespace UI
} // namespace Onsang
<commit_msg>UI::TabbedContainer: added get_tabs().<commit_after>/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Tabbed container.
*/

#pragma once

#include <Onsang/config.hpp>
#include <Onsang/aux.hpp>
#include <Onsang/utility.hpp>
#include <Onsang/UI/Defs.hpp>

#include <Beard/ui/Widget/Base.hpp>
#include <Beard/ui/Root.hpp>

namespace Onsang {
namespace UI {

// Forward declarations
class TabbedContainer;

/**
	Prototype slot-based container widget.
*/
class TabbedContainer
	: public UI::Widget::Base
{
public:
	using SPtr = aux::shared_ptr<UI::TabbedContainer>;

private:
	using base = UI::Widget::Base;
	enum class ctor_priv {};

	struct Tab {
		String title;
		UI::Widget::SPtr widget;
	};

	unsigned m_position;
	aux::vector<Tab> m_tabs;

	TabbedContainer() noexcept = delete;
	TabbedContainer(TabbedContainer const&) = delete;
	TabbedContainer& operator=(TabbedContainer const&) = delete;

	void push_back(UI::Widget::SPtr /*widget*/) {}

protected:
// Beard::ui::Widget::Base implementation
	void
	cache_geometry_impl() noexcept override {
		auto rs = get_geometry().get_request_size();
		if (!m_tabs.empty()) {
			Tab const& tab = m_tabs.at(m_position);
			if (tab.widget) {
				tab.widget->cache_geometry();
				auto const& ws = tab.widget->get_geometry().get_request_size();
				rs.width  = max_ce(rs.width , ws.width);
				rs.height = max_ce(rs.height, ws.height);
			}
		}
		if (!get_geometry().is_static()) {
			get_geometry().set_request_size(std::move(rs));
		}
	}

	void
	reflow_impl(
		Rect const& area,
		bool const cache
	) noexcept override {
		base::reflow_impl(area, cache);
		if (m_tabs.empty()) {
			return;
		}
		Rect child_frame = area;
		++child_frame.pos.y;
		--child_frame.size.height;
		vec2_clamp_min(child_frame.size, Vec2{0, 0});
		unsigned index = 0;
		for (auto& tab : m_tabs) {
			if (index == m_position) {
				tab.widget->reflow(child_frame, false);
			}
			++index;
		}
	}

	void
	render_impl(
		UI::Widget::RenderData& rd
	) noexcept override {
		if (m_tabs.empty()) {
			 return;
		}
		auto const& frame = get_geometry().get_frame();
		unsigned index = 0;
		signed xpos = 0;
		for (auto& tab : m_tabs) {
			bool const active = index == m_position;
			rd.terminal.put_sequence(
				frame.pos.x + xpos,
				frame.pos.y,
				Beard::txt::Sequence{tab.title, 0u, tab.title.size()},
				unsigned_cast(max_ce(0, frame.size.width)),
				rd.get_attr(active
					? ui::property_content_fg_selected
					: ui::property_content_fg_inactive
				),
				rd.get_attr(active
					? ui::property_content_bg_selected
					: ui::property_content_bg_inactive
				)
			);
			if (active) {
				tab.widget->render(rd);
			}
			if (index + 1 != m_tabs.size()) {
				xpos += tab.title.size() + 1;
				rd.terminal.put_cell(
					frame.pos.x + xpos,
					frame.pos.y,
					Beard::tty::make_cell(
						U'│',
						Beard::tty::Attr::bold |
						Beard::tty::Color::blue,
						Beard::tty::Color::term_default
					)
				);
				xpos += 2;
			}
			++index;
		}
	}

	signed
	num_children_impl() const noexcept override {
		return static_cast<signed>(m_tabs.size());
	}

	UI::Widget::SPtr
	get_child_impl(
		signed const index
	) override {
		return m_tabs.at(static_cast<unsigned>(index)).widget;
	}

public:
// special member functions
	~TabbedContainer() noexcept override = default;

	TabbedContainer(
		ctor_priv const,
		UI::RootWPtr&& root,
		UI::Widget::WPtr&& parent
	) noexcept
		: base(
			static_cast<UI::Widget::Type>(UI::OnsangWidgetType::TabbedContainer),
			enum_combine(
				UI::Widget::Flags::trait_container,
				UI::Widget::Flags::visible
			),
			UI::group_null,
			{{0, 0}, true, UI::Axis::both, UI::Axis::both},
			std::move(root),
			std::move(parent)
		)
		, m_position(0)
		, m_tabs()
	{}

	TabbedContainer(TabbedContainer&&) = default;
	TabbedContainer& operator=(TabbedContainer&&) = default;

	static UI::TabbedContainer::SPtr
	make(
		UI::RootWPtr root,
		UI::Widget::WPtr parent = UI::Widget::WPtr()
	) {
		return aux::make_shared<UI::TabbedContainer>(
			ctor_priv{},
			std::move(root),
			std::move(parent)
		);
	}

// properties
	bool
	empty() const noexcept {
		return m_tabs.empty();
	}

	aux::vector<Tab> const&
	get_tabs() const noexcept {
		return m_tabs;
	}

	unsigned
	get_tab() const noexcept {
		return m_position;
	}

	unsigned
	get_last_index() const noexcept {
		return m_tabs.empty()
			? 0
			: static_cast<unsigned>(m_tabs.size() - 1)
		;
	}

// operations
	void
	push_back(
		String title,
		UI::Widget::SPtr&& widget
	) {
		insert(std::move(title), std::move(widget), m_tabs.size());
		set_current_tab(get_last_index());
	}

	void
	insert(
		String title,
		UI::Widget::SPtr widget,
		unsigned index
	) {
		index = min_ce(index, static_cast<unsigned>(m_tabs.size()));
		widget->set_parent(shared_from_this(), index);
		if (m_tabs.empty()) {
			m_position = 0;
			widget->set_visible(true);
		} else if (index <= m_position) {
			++m_position;
			widget->set_visible(false);
		}
		m_tabs.insert(
			m_tabs.cbegin() + index,
			Tab{std::move(title), std::move(widget)}
		);
		for (; m_tabs.size() > index; ++index) {
			m_tabs[index].widget->set_index(static_cast<UI::index_type>(index));
		}
		queue_actions(enum_combine(
			UI::UpdateActions::reflow,
			UI::UpdateActions::render
		));
	}

	void
	remove(
		unsigned index
	) {
		m_tabs.erase(m_tabs.cbegin() + index);
		m_position = min_ce(m_position, get_last_index());
		for (; m_tabs.size() > index; ++index) {
			m_tabs[index].widget->set_index(static_cast<UI::index_type>(index));
		}
		if (!m_tabs.empty()) {
			m_tabs[m_position].widget->set_visible(true);
		}
		queue_actions(enum_combine(
			UI::UpdateActions::reflow,
			UI::UpdateActions::render
		));
	}

	void
	remove_current() {
		if (!m_tabs.empty()) {
			get_root()->clear_focus();
			remove(m_position);
		}
	}

	void
	clear() {
		m_tabs.clear();
		m_position = 0;
		queue_actions(enum_combine(
			UI::UpdateActions::reflow,
			UI::UpdateActions::render
		));
	}

	void
	set_title(
		unsigned const index,
		String title
	) {
		m_tabs.at(index).title = std::move(title);
		queue_actions(enum_combine(
			UI::UpdateActions::reflow,
			UI::UpdateActions::render
		));
	}

	void
	set_tab(
		std::size_t const index,
		UI::Widget::SPtr widget
	) {
		m_tabs.at(index).widget = std::move(widget);
	}

	void
	set_current_tab(
		unsigned index
	) {
		index = min_ce(index, get_last_index());
		if (!m_tabs.empty() && index != m_position) {
			// TODO: Track focused widget per-tab
			get_root()->clear_focus();
			m_tabs[m_position].widget->set_visible(false);
			m_tabs[index].widget->set_visible(true);
			m_position = index;
			queue_actions(enum_combine(
				UI::UpdateActions::reflow,
				UI::UpdateActions::render
			));
		}
	}

	void
	prev_tab() {
		if (0 < m_position) {
			set_current_tab(m_position - 1);
		}
	}

	void
	next_tab() {
		set_current_tab(m_position + 1);
	}

	void
	move_tab(
		unsigned from,
		unsigned to,
		bool const insert = false
	) {
		from = min_ce(from, get_last_index());
		to = min_ce(to, get_last_index());
		if (from != to) {
			if (insert) {
				Tab tab = m_tabs[from];
				m_tabs.erase(m_tabs.cbegin() + from);
				m_tabs.insert(m_tabs.cbegin() + to, std::move(tab));
				for (
					unsigned index = min_ce(from, to);
					m_tabs.size() > index;
					++index
				) {
					m_tabs[index].widget->set_index(static_cast<UI::index_type>(index));
				}
			} else {
				m_tabs[from].widget->set_index(to);
				m_tabs[to].widget->set_index(from);
				std::swap(m_tabs[from], m_tabs[to]);
			}
			if (from == m_position) {
				m_position = to;
			}
			queue_actions(enum_combine(
				UI::UpdateActions::flag_noclear,
				UI::UpdateActions::render
			));
		}
	}

	void
	move_left(
		unsigned const index,
		bool const insert = false
	) {
		if (index > 0) {
			move_tab(index, index - 1, insert);
		}
	}

	void
	move_right(
		unsigned const index,
		bool const insert = false
	) {
		move_tab(index, index + 1, insert);
	}
};

} // namespace UI
} // namespace Onsang
<|endoftext|>


<commit_before>/*
 * SessionPdfLatex.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionPdfLatex.hpp"

#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>

#include <core/system/Environment.hpp>
#include <core/FileSerializer.hpp>

#include <session/projects/SessionProjects.hpp>

#include <session/SessionUserSettings.hpp>
#include <session/SessionModuleContext.hpp>

#include "SessionTexUtils.hpp"

using namespace core;

namespace session {
namespace modules {
namespace tex {
namespace pdflatex {

namespace {

class LatexProgramTypes : boost::noncopyable
{
public:
   LatexProgramTypes()
   {
      types_.push_back("pdfLaTeX");
      types_.push_back("XeLaTeX");
   }

   const std::vector<std::string>& allTypes() const
   {
      return types_;
   }

   json::Array allTypesAsJson() const
   {
      json::Array typesJson;
      std::transform(types_.begin(),
                     types_.end(),
                     std::back_inserter(typesJson),
                     json::toJsonString);
      return typesJson;
   }

   bool isValidTypeName(const std::string& name) const
   {
      BOOST_FOREACH(const std::string& type, types_)
      {
         if (boost::algorithm::iequals(name, type))
            return true;
      }

      return false;
   }

   std::string printableTypeNames() const
   {
      if (types_.size() == 1)
         return types_[0];
      else if (types_.size() == 2)
         return types_[0] + " and " + types_[1];
      else
      {
         std::string str;
         for (std::size_t i=0; i<types_.size(); i++)
         {
            str.append(types_[i]);
            if (i != (types_.size() - 1))
               str.append(", ");
            if (i == (types_.size() - 2))
               str.append("and ");
         }
         return str;
      }
   }

private:
   std::vector<std::string> types_;
};

const LatexProgramTypes& programTypes()
{
   static LatexProgramTypes instance;
   return instance;
}

std::string latexProgramMagicComment(
                     const core::tex::TexMagicComments& magicComments)
{
   BOOST_FOREACH(const core::tex::TexMagicComment& mc, magicComments)
   {
      if (boost::algorithm::iequals(mc.scope(), "tex") &&
          (boost::algorithm::iequals(mc.variable(), "program") ||
           boost::algorithm::iequals(mc.variable(), "ts-program")))
      {
         return mc.value();
      }
   }

   return std::string();
}

void setInvalidProgramTypeMessage(const std::string& program,
                                  std::string* pUserErrMsg)
{
   *pUserErrMsg = "Unknown LaTeX program type '" + program +
                  "' specified (valid types are " +
                  programTypes().printableTypeNames() + ")";
}

bool validateLatexProgram(const std::string& program,
                          FilePath* pTexProgramPath,
                          std::string* pUserErrMsg)
{
   // convert to lower case for finding
   std::string programName = string_utils::toLower(program);

   // try to find on the path
   *pTexProgramPath = module_context::findProgram(programName);
   if (pTexProgramPath->empty())
   {
      *pUserErrMsg = "Unabled to find specified LaTeX program '" +
                     program + "' on the system path";
      return false;
   }
   else
   {
      return true;
   }
}

bool validateLatexProgramType(const std::string& programType,
                              std::string* pUserErrMsg)
{
   if (!programTypes().isValidTypeName(programType))
   {
      setInvalidProgramTypeMessage(programType, pUserErrMsg);
      return false;
   }
   else
   {
      return true;
   }
}

void appendEnvVarNotice(std::string* pUserErrMsg)
{
   pUserErrMsg->append(" (the program was specified using the "
                       "RSTUDIO_PDFLATEX environment variable)");
}

shell_utils::ShellArgs shellArgs(const PdfLatexOptions& options)
{
   shell_utils::ShellArgs args;

   if (options.fileLineError)
   {
      if (options.isMikTeX())
         args << kCStyleErrorsOption;
      else
         args << kFileLineErrorOption;
   }
   if (options.syncTex)
   {
      args << kSynctexOption;
   }
   if (options.shellEscape)
   {
      if (options.isMikTeX())
         args << kEnableWrite18Option;
      else
         args << kShellEscapeOption;
   }
   args << "-interaction=nonstopmode";

   return args;
}

FilePath programPath(const std::string& name, const std::string& envOverride)
{
   std::string envProgram = core::system::getenv(envOverride);
   std::string program = envProgram.empty() ? name : envProgram;
   return module_context::findProgram(program);
}

bool lineIncludes(const std::string& line, const boost::regex& regex)
{
    boost::smatch match;
    return boost::regex_search(line, match, regex);
}

int countCitationMisses(const FilePath& logFilePath)
{
   // read the log file
   std::vector<std::string> lines;
   Error error = core::readStringVectorFromFile(logFilePath, &lines);
   if (error)
   {
      LOG_ERROR(error);
      return 0;
   }

   // look for misses
   boost::regex missRegex("Warning:.*Citation.*undefined");
   int misses = std::count_if(lines.begin(),
                              lines.end(),
                              boost::bind(lineIncludes, _1, missRegex));
   return misses;
}

bool logIncludesRerun(const FilePath& logFilePath)
{
   std::string logContents;
   Error error = core::readStringFromFile(logFilePath, &logContents);
   if (error)
   {
      LOG_ERROR(error);
      return false;
   }

   return logContents.find("Rerun to get") != std::string::npos;
}

} // anonymous namespace

const char * const kFileLineErrorOption = "-file-line-error";
const char * const kCStyleErrorsOption = "-c-style-errors";
const char * const kShellEscapeOption = "-shell-escape";
const char * const kEnableWrite18Option = "–enable-write18";
const char * const kSynctexOption = "-synctex=-1";

bool isInstalled()
{
   return !module_context::findProgram("pdflatex").empty();
}

core::json::Array supportedTypes()
{
   return programTypes().allTypesAsJson();
}

bool latexProgramForFile(const core::tex::TexMagicComments& magicComments,
                         FilePath* pTexProgramPath,
                         std::string* pUserErrMsg)
{
   // get (optional) magic comments and environment variable override
   std::string latexProgramMC = latexProgramMagicComment(magicComments);
   std::string pdflatexEnv = core::system::getenv("RSTUDIO_PDFLATEX");

   // magic comment always takes highest priority
   if (!latexProgramMC.empty())
   {
      // validate magic comment
      if (!validateLatexProgramType(latexProgramMC, pUserErrMsg))
      {
         return false;
      }
      else
      {
         return validateLatexProgram(latexProgramMC,
                                     pTexProgramPath,
                                     pUserErrMsg);
      }
   }

   // next is environment variable
   else if (!pdflatexEnv.empty())
   {
      if (FilePath::isRootPath(pdflatexEnv))
      {
         FilePath texProgramPath(pdflatexEnv);
         if (texProgramPath.exists())
         {
            *pTexProgramPath = texProgramPath;
            return true;
         }
         else
         {
            *pUserErrMsg = "Unabled to find specified LaTeX program " +
                           pdflatexEnv;
            appendEnvVarNotice(pUserErrMsg);
            return false;
         }
      }
      else
      {
         bool validated = validateLatexProgram(pdflatexEnv,
                                               pTexProgramPath,
                                               pUserErrMsg);

         if (!validated)
            appendEnvVarNotice(pUserErrMsg);

         return validated;
      }
   }

   // project or global default setting
   else
   {
      std::string defaultProgram = projects::projectContext().hasProject() ?
                projects::projectContext().config().defaultLatexProgram :
                userSettings().defaultLatexProgram();

      if (!validateLatexProgramType(defaultProgram, pUserErrMsg))
      {
         return false;
      }
      else
      {
         return validateLatexProgram(defaultProgram,
                                     pTexProgramPath,
                                     pUserErrMsg);
      }
   }
}

// this function provides an "emulated" version of texi2dvi for when the
// user has texi2dvi disabled. For example to workaround this bug:
//
//  http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=534458
//
// this code is a port of the simillar logic which exists in the
// tools::texi2dvi function (but the regex for detecting citation
// warnings was made a bit more liberal)
//
core::Error texToPdf(const core::FilePath& texProgramPath,
                     const core::FilePath& texFilePath,
                     const tex::pdflatex::PdfLatexOptions& options,
                     core::system::ProcessResult* pResult)
{
   // input file paths
   FilePath baseFilePath = texFilePath.parent().complete(texFilePath.stem());
   FilePath idxFilePath(baseFilePath.absolutePath() + ".idx");
   FilePath logFilePath(baseFilePath.absolutePath() + ".log");

   // bibtex and makeindex program paths
   FilePath bibtexProgramPath = programPath("bibtex", "BIBTEX");
   FilePath makeindexProgramPath = programPath("makeindex", "MAKEINDEX");

   // args and process options for running bibtex and makeindex
   core::shell_utils::ShellArgs bibtexArgs;
   bibtexArgs << string_utils::utf8ToSystem(baseFilePath.filename());
   core::shell_utils::ShellArgs makeindexArgs;
   makeindexArgs << string_utils::utf8ToSystem(idxFilePath.filename());
   core::system::ProcessOptions procOptions;
   procOptions.environment = utils::rTexInputsEnvVars();
   procOptions.workingDir = texFilePath.parent();

   // run the initial compile
   Error error = utils::runTexCompile(texProgramPath,
                                      utils::rTexInputsEnvVars(),
                                      shellArgs(options),
                                      texFilePath,
                                      pResult);
   if (error)
      return error;

   // count misses
   int misses = countCitationMisses(logFilePath);
   int previousMisses = 0;

   // resolve citation misses and index
   for (int i=0; i<10; i++)
   {
      // run bibtex if necessary
      if (misses > 0 && !bibtexProgramPath.empty())
      {
         core::system::ProcessResult result;
         Error error = core::system::runProgram(
               string_utils::utf8ToSystem(bibtexProgramPath.absolutePath()),
               bibtexArgs,
               "",
               procOptions,
               pResult);
         if (error)
            LOG_ERROR(error);
         else if (pResult->exitStatus != EXIT_SUCCESS)
            return Success(); // pass error state on to caller
      }
      previousMisses = misses;

      // run makeindex if necessary
      if (idxFilePath.exists() && !makeindexProgramPath.empty())
      {
         Error error = core::system::runProgram(
               string_utils::utf8ToSystem(makeindexProgramPath.absolutePath()),
               makeindexArgs,
               "",
               procOptions,
               pResult);
         if (error)
            LOG_ERROR(error);
         else if (pResult->exitStatus != EXIT_SUCCESS)
            return Success(); // pass error state on to caller
      }

      // re-run latex
      Error error = utils::runTexCompile(texProgramPath,
                                         utils::rTexInputsEnvVars(),
                                         shellArgs(options),
                                         texFilePath,
                                         pResult);
      if (error)
         return error;

      // count misses
      misses = countCitationMisses(logFilePath);

      // if there is no change in misses and there is no "Rerun to get"
      // in the log file then break
      if ((misses == previousMisses) && !logIncludesRerun(logFilePath))
         break;
   }

   return Success();
}

} // namespace pdflatex
} // namespace tex
} // namespace modules
} // namesapce session

<commit_msg>only re-run tex compile if we had to run bibtex or makeindex<commit_after>/*
 * SessionPdfLatex.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionPdfLatex.hpp"

#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>

#include <core/system/Environment.hpp>
#include <core/FileSerializer.hpp>

#include <session/projects/SessionProjects.hpp>

#include <session/SessionUserSettings.hpp>
#include <session/SessionModuleContext.hpp>

#include "SessionTexUtils.hpp"

using namespace core;

namespace session {
namespace modules {
namespace tex {
namespace pdflatex {

namespace {

class LatexProgramTypes : boost::noncopyable
{
public:
   LatexProgramTypes()
   {
      types_.push_back("pdfLaTeX");
      types_.push_back("XeLaTeX");
   }

   const std::vector<std::string>& allTypes() const
   {
      return types_;
   }

   json::Array allTypesAsJson() const
   {
      json::Array typesJson;
      std::transform(types_.begin(),
                     types_.end(),
                     std::back_inserter(typesJson),
                     json::toJsonString);
      return typesJson;
   }

   bool isValidTypeName(const std::string& name) const
   {
      BOOST_FOREACH(const std::string& type, types_)
      {
         if (boost::algorithm::iequals(name, type))
            return true;
      }

      return false;
   }

   std::string printableTypeNames() const
   {
      if (types_.size() == 1)
         return types_[0];
      else if (types_.size() == 2)
         return types_[0] + " and " + types_[1];
      else
      {
         std::string str;
         for (std::size_t i=0; i<types_.size(); i++)
         {
            str.append(types_[i]);
            if (i != (types_.size() - 1))
               str.append(", ");
            if (i == (types_.size() - 2))
               str.append("and ");
         }
         return str;
      }
   }

private:
   std::vector<std::string> types_;
};

const LatexProgramTypes& programTypes()
{
   static LatexProgramTypes instance;
   return instance;
}

std::string latexProgramMagicComment(
                     const core::tex::TexMagicComments& magicComments)
{
   BOOST_FOREACH(const core::tex::TexMagicComment& mc, magicComments)
   {
      if (boost::algorithm::iequals(mc.scope(), "tex") &&
          (boost::algorithm::iequals(mc.variable(), "program") ||
           boost::algorithm::iequals(mc.variable(), "ts-program")))
      {
         return mc.value();
      }
   }

   return std::string();
}

void setInvalidProgramTypeMessage(const std::string& program,
                                  std::string* pUserErrMsg)
{
   *pUserErrMsg = "Unknown LaTeX program type '" + program +
                  "' specified (valid types are " +
                  programTypes().printableTypeNames() + ")";
}

bool validateLatexProgram(const std::string& program,
                          FilePath* pTexProgramPath,
                          std::string* pUserErrMsg)
{
   // convert to lower case for finding
   std::string programName = string_utils::toLower(program);

   // try to find on the path
   *pTexProgramPath = module_context::findProgram(programName);
   if (pTexProgramPath->empty())
   {
      *pUserErrMsg = "Unabled to find specified LaTeX program '" +
                     program + "' on the system path";
      return false;
   }
   else
   {
      return true;
   }
}

bool validateLatexProgramType(const std::string& programType,
                              std::string* pUserErrMsg)
{
   if (!programTypes().isValidTypeName(programType))
   {
      setInvalidProgramTypeMessage(programType, pUserErrMsg);
      return false;
   }
   else
   {
      return true;
   }
}

void appendEnvVarNotice(std::string* pUserErrMsg)
{
   pUserErrMsg->append(" (the program was specified using the "
                       "RSTUDIO_PDFLATEX environment variable)");
}

shell_utils::ShellArgs shellArgs(const PdfLatexOptions& options)
{
   shell_utils::ShellArgs args;

   if (options.fileLineError)
   {
      if (options.isMikTeX())
         args << kCStyleErrorsOption;
      else
         args << kFileLineErrorOption;
   }
   if (options.syncTex)
   {
      args << kSynctexOption;
   }
   if (options.shellEscape)
   {
      if (options.isMikTeX())
         args << kEnableWrite18Option;
      else
         args << kShellEscapeOption;
   }
   args << "-interaction=nonstopmode";

   return args;
}

FilePath programPath(const std::string& name, const std::string& envOverride)
{
   std::string envProgram = core::system::getenv(envOverride);
   std::string program = envProgram.empty() ? name : envProgram;
   return module_context::findProgram(program);
}

bool lineIncludes(const std::string& line, const boost::regex& regex)
{
    boost::smatch match;
    return boost::regex_search(line, match, regex);
}

int countCitationMisses(const FilePath& logFilePath)
{
   // read the log file
   std::vector<std::string> lines;
   Error error = core::readStringVectorFromFile(logFilePath, &lines);
   if (error)
   {
      LOG_ERROR(error);
      return 0;
   }

   // look for misses
   boost::regex missRegex("Warning:.*Citation.*undefined");
   int misses = std::count_if(lines.begin(),
                              lines.end(),
                              boost::bind(lineIncludes, _1, missRegex));
   return misses;
}

bool logIncludesRerun(const FilePath& logFilePath)
{
   std::string logContents;
   Error error = core::readStringFromFile(logFilePath, &logContents);
   if (error)
   {
      LOG_ERROR(error);
      return false;
   }

   return logContents.find("Rerun to get") != std::string::npos;
}

} // anonymous namespace

const char * const kFileLineErrorOption = "-file-line-error";
const char * const kCStyleErrorsOption = "-c-style-errors";
const char * const kShellEscapeOption = "-shell-escape";
const char * const kEnableWrite18Option = "–enable-write18";
const char * const kSynctexOption = "-synctex=-1";

bool isInstalled()
{
   return !module_context::findProgram("pdflatex").empty();
}

core::json::Array supportedTypes()
{
   return programTypes().allTypesAsJson();
}

bool latexProgramForFile(const core::tex::TexMagicComments& magicComments,
                         FilePath* pTexProgramPath,
                         std::string* pUserErrMsg)
{
   // get (optional) magic comments and environment variable override
   std::string latexProgramMC = latexProgramMagicComment(magicComments);
   std::string pdflatexEnv = core::system::getenv("RSTUDIO_PDFLATEX");

   // magic comment always takes highest priority
   if (!latexProgramMC.empty())
   {
      // validate magic comment
      if (!validateLatexProgramType(latexProgramMC, pUserErrMsg))
      {
         return false;
      }
      else
      {
         return validateLatexProgram(latexProgramMC,
                                     pTexProgramPath,
                                     pUserErrMsg);
      }
   }

   // next is environment variable
   else if (!pdflatexEnv.empty())
   {
      if (FilePath::isRootPath(pdflatexEnv))
      {
         FilePath texProgramPath(pdflatexEnv);
         if (texProgramPath.exists())
         {
            *pTexProgramPath = texProgramPath;
            return true;
         }
         else
         {
            *pUserErrMsg = "Unabled to find specified LaTeX program " +
                           pdflatexEnv;
            appendEnvVarNotice(pUserErrMsg);
            return false;
         }
      }
      else
      {
         bool validated = validateLatexProgram(pdflatexEnv,
                                               pTexProgramPath,
                                               pUserErrMsg);

         if (!validated)
            appendEnvVarNotice(pUserErrMsg);

         return validated;
      }
   }

   // project or global default setting
   else
   {
      std::string defaultProgram = projects::projectContext().hasProject() ?
                projects::projectContext().config().defaultLatexProgram :
                userSettings().defaultLatexProgram();

      if (!validateLatexProgramType(defaultProgram, pUserErrMsg))
      {
         return false;
      }
      else
      {
         return validateLatexProgram(defaultProgram,
                                     pTexProgramPath,
                                     pUserErrMsg);
      }
   }
}

// this function provides an "emulated" version of texi2dvi for when the
// user has texi2dvi disabled. For example to workaround this bug:
//
//  http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=534458
//
// this code is a port of the simillar logic which exists in the
// tools::texi2dvi function (but the regex for detecting citation
// warnings was made a bit more liberal)
//
core::Error texToPdf(const core::FilePath& texProgramPath,
                     const core::FilePath& texFilePath,
                     const tex::pdflatex::PdfLatexOptions& options,
                     core::system::ProcessResult* pResult)
{
   // input file paths
   FilePath baseFilePath = texFilePath.parent().complete(texFilePath.stem());
   FilePath idxFilePath(baseFilePath.absolutePath() + ".idx");
   FilePath logFilePath(baseFilePath.absolutePath() + ".log");

   // bibtex and makeindex program paths
   FilePath bibtexProgramPath = programPath("bibtex", "BIBTEX");
   FilePath makeindexProgramPath = programPath("makeindex", "MAKEINDEX");

   // args and process options for running bibtex and makeindex
   core::shell_utils::ShellArgs bibtexArgs;
   bibtexArgs << string_utils::utf8ToSystem(baseFilePath.filename());
   core::shell_utils::ShellArgs makeindexArgs;
   makeindexArgs << string_utils::utf8ToSystem(idxFilePath.filename());
   core::system::ProcessOptions procOptions;
   procOptions.environment = utils::rTexInputsEnvVars();
   procOptions.workingDir = texFilePath.parent();

   // run the initial compile
   Error error = utils::runTexCompile(texProgramPath,
                                      utils::rTexInputsEnvVars(),
                                      shellArgs(options),
                                      texFilePath,
                                      pResult);
   if (error)
      return error;

   // count misses
   int misses = countCitationMisses(logFilePath);
   int previousMisses = 0;

   // resolve citation misses and index
   for (int i=0; i<10; i++)
   {
      // do we need to re-run at the end of the loop iteration
      bool reRunTexCompile = false;

      // run bibtex if necessary
      if (misses > 0 && !bibtexProgramPath.empty())
      {
         reRunTexCompile = true;

         core::system::ProcessResult result;
         Error error = core::system::runProgram(
               string_utils::utf8ToSystem(bibtexProgramPath.absolutePath()),
               bibtexArgs,
               "",
               procOptions,
               pResult);
         if (error)
            LOG_ERROR(error);
         else if (pResult->exitStatus != EXIT_SUCCESS)
            return Success(); // pass error state on to caller
      }
      previousMisses = misses;

      // run makeindex if necessary
      if (idxFilePath.exists() && !makeindexProgramPath.empty())
      {
         reRunTexCompile = true;

         Error error = core::system::runProgram(
               string_utils::utf8ToSystem(makeindexProgramPath.absolutePath()),
               makeindexArgs,
               "",
               procOptions,
               pResult);
         if (error)
            LOG_ERROR(error);
         else if (pResult->exitStatus != EXIT_SUCCESS)
            return Success(); // pass error state on to caller
      }

      // re-run latex
      if (reRunTexCompile)
      {
         Error error = utils::runTexCompile(texProgramPath,
                                            utils::rTexInputsEnvVars(),
                                            shellArgs(options),
                                            texFilePath,
                                            pResult);
         if (error)
            return error;

         // count misses
         misses = countCitationMisses(logFilePath);
      }

      // if there is no change in misses and there is no "Rerun to get"
      // in the log file then break
      if ((misses == previousMisses) && !logIncludesRerun(logFilePath))
         break;
   }

   return Success();
}

} // namespace pdflatex
} // namespace tex
} // namespace modules
} // namesapce session

<|endoftext|>


<commit_before>/*
*
* Copyright (C) 2004 Mekensleep
*
*    Mekensleep
*    24 rue vieille du temple
*    75004 Paris
*       licensing@mekensleep.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* Author:
*  Igor Kravtchenko <igor@obraz.net>
*
*/

#include "hdrloader.h"

#include <math.h>
#include <memory.h>
#include <stdio.h>

#include <osgDB/FileUtils>

typedef unsigned char RGBE[4];
#define R            0
#define G            1
#define B            2
#define E            3

#define  MINELEN    8                // minimum scanline length for encoding
#define  MAXELEN    0x7fff            // maximum scanline length for encoding

static void rawRGBEData(RGBE *scan, int len, float *cols);
static void workOnRGBE(RGBE *scan, int len, float *cols);
static bool decrunch(RGBE *scanline, int len, FILE *file);
static bool oldDecrunch(RGBE *scanline, int len, FILE *file);

inline char read_char(FILE* stream, int& error)
{
    if (error) return 0;

    int value = fgetc(stream);
    if (value>=0 && value<128)
    {
        return static_cast<char>(value);
    }
    else
    {
        error = value;
        return 0;
    }
}

inline unsigned char read_unsigned_char(FILE* stream, int& error)
{
    if (error) return 0;

    int value = fgetc(stream);
    if (value>=0 && value<256)
    {
        return static_cast<unsigned char>(value);
    }
    else
    {
        error = value;
        return 0;
    }
}

bool HDRLoader::isHDRFile(const char *_fileName)
{
    FILE *file;
    file = osgDB::fopen(_fileName, "rb");
    if (!file)
        return false;

    char str[10];
    size_t numRead = fread(str, 10, 1, file);

    fclose(file);

    if (numRead<1) return false;

    if (memcmp(str, "#?RADIANCE", 10) && memcmp(str, "#?RGBE", 6))
        return false;

    return true;
}

bool HDRLoader::load(const char *_fileName, const bool _rawRGBE, HDRLoaderResult &_res)
{
    int i;
    char str[200];
    FILE *file;

    file = osgDB::fopen(_fileName, "rb");
    if (!file)
        return false;

    size_t numRead = fread(str, 10, 1, file);

    if (numRead<1)
    {
        fclose(file);
        return false;
    }

    if (memcmp(str, "#?RADIANCE", 10))
    {
        if (fseek(file, 0, SEEK_SET)!=0)
        {
            fclose(file);
            return false;
        }

        numRead = fread(str, 6, 1, file);
        if (numRead<1 || memcmp(str, "#?RGBE", 6))
        {
            fclose(file);
            return false;
        }
    }
    if (fseek(file, 1, SEEK_CUR)!=0)
    {
        fclose(file);
        return false;
    }

    //char cmd[2000];
    i = 0;
    char c = 0, oldc;
    int error = 0;
    while(!error) {
        oldc = c;
        c = read_char(file, error);
        if (c == 0xa && oldc == 0xa)
            break;
        //cmd[i++] = c;
    }

    char reso[2000];
    i = 0;
    while(!error) {
        c = read_char(file, error);
        reso[i++] = c;
        if (c == 0xa)
            break;
    }

    int w, h;
    if (!sscanf(reso, "-Y %d +X %d", &h, &w)) {
        fclose(file);
        return false;
    }

    _res.width = w;
    _res.height = h;

    int components = _rawRGBE ? 4 : 3;
    float *cols = new float[w * h * components];
    _res.cols = cols;

    RGBE *scanline = new RGBE[w];
    if (!scanline) {
        fclose(file);
        return false;
    }

    // convert image
    cols += (h-1) * w * components;
    for (int y = h - 1; y >= 0; y--) {
        if (decrunch(scanline, w, file) == false)
            break;
        if (_rawRGBE)
            rawRGBEData(scanline, w, cols);
        else
            workOnRGBE(scanline, w, cols);
        cols -= w * components;
    }

    delete [] scanline;
    fclose(file);

    return true;
}

void rawRGBEData(RGBE *_scan, int _len, float *_cols)
{
    int ii = 0;
    while (_len-- > 0) {
        _cols[0] = _scan[0][R] / 255.0f;
        _cols[1] = _scan[0][G] / 255.0f;
        _cols[2] = _scan[0][B] / 255.0f;
        _cols[3] = _scan[0][E] / 255.0f;
        _cols += 4;
        _scan++;
        ii++;
    }
}

inline float convertComponent(int _expo, int _val)
{
    return static_cast<float>(ldexp( static_cast<float>(_val), _expo-8));
}

void workOnRGBE(RGBE *_scan, int _len, float *_cols)
{
    int ii = 0;
    while (_len-- > 0) {
        int expo = _scan[0][E] - 128;
        _cols[0] = convertComponent(expo, _scan[0][R]);
        _cols[1] = convertComponent(expo, _scan[0][G]);
        _cols[2] = convertComponent(expo, _scan[0][B]);
        _cols += 3;
        _scan++;
        ii++;
    }
}

bool decrunch(RGBE *_scanline, int _len, FILE *_file)
{
    int  i, j;

    if (_len < MINELEN || _len > MAXELEN)
        return oldDecrunch(_scanline, _len, _file);

    i = fgetc(_file);
    if (i != 2) {
        fseek(_file, -1, SEEK_CUR);
        return oldDecrunch(_scanline, _len, _file);
    }

    int error = 0;

    _scanline[0][G] = read_unsigned_char(_file, error);
    _scanline[0][B] = read_unsigned_char(_file, error);
    i = fgetc(_file);

    if (_scanline[0][G] != 2 || _scanline[0][B] & 128) {
        _scanline[0][R] = 2;
        _scanline[0][E] = i;
        return oldDecrunch(_scanline + 1, _len - 1, _file);
    }

    // read each component
    for (i = 0; i < 4; i++) {
        for (j = 0; j < _len; ) {
            unsigned char code = read_unsigned_char(_file, error);
            if (code > 128) { // run
                code &= 127;
                unsigned char val = read_unsigned_char(_file, error);
                while (code--)
                    _scanline[j++][i] = val;
            }
            else  {    // non-run
                while(code--)
                    _scanline[j++][i] = read_unsigned_char(_file, error);
            }
        }
    }

    return feof(_file) ? false : true;
}

bool oldDecrunch(RGBE *_scanline, int _len, FILE *_file)
{
    int i;
    int rshift = 0;

    int error = 0;

    while (_len > 0 && !error) {
        _scanline[0][R] = read_unsigned_char(_file, error);
        _scanline[0][G] = read_unsigned_char(_file, error);
        _scanline[0][B] = read_unsigned_char(_file, error);
        _scanline[0][E] = read_unsigned_char(_file, error);
        if (feof(_file))
            return false;

        if (_scanline[0][R] == 1 &&
            _scanline[0][G] == 1 &&
            _scanline[0][B] == 1) {
                for (i = _scanline[0][E] << rshift; i > 0; i--) {
                    memcpy(&_scanline[0][0], &_scanline[-1][0], 4);
                    _scanline++;
                    _len--;
                }
                rshift += 8;
            }
        else {
            _scanline++;
            _len--;
            rshift = 0;
        }
    }
    return true;
}
<commit_msg>Added handling of return type<commit_after>/*
*
* Copyright (C) 2004 Mekensleep
*
*    Mekensleep
*    24 rue vieille du temple
*    75004 Paris
*       licensing@mekensleep.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* Author:
*  Igor Kravtchenko <igor@obraz.net>
*
*/

#include "hdrloader.h"

#include <math.h>
#include <memory.h>
#include <stdio.h>

#include <osgDB/FileUtils>

typedef unsigned char RGBE[4];
#define R            0
#define G            1
#define B            2
#define E            3

#define  MINELEN    8                // minimum scanline length for encoding
#define  MAXELEN    0x7fff            // maximum scanline length for encoding

static void rawRGBEData(RGBE *scan, int len, float *cols);
static void workOnRGBE(RGBE *scan, int len, float *cols);
static bool decrunch(RGBE *scanline, int len, FILE *file);
static bool oldDecrunch(RGBE *scanline, int len, FILE *file);

inline char read_char(FILE* stream, int& error)
{
    if (error) return 0;

    int value = fgetc(stream);
    if (value>=0 && value<128)
    {
        return static_cast<char>(value);
    }
    else
    {
        error = value;
        return 0;
    }
}

inline unsigned char read_unsigned_char(FILE* stream, int& error)
{
    if (error) return 0;

    int value = fgetc(stream);
    if (value>=0 && value<256)
    {
        return static_cast<unsigned char>(value);
    }
    else
    {
        error = value;
        return 0;
    }
}

bool HDRLoader::isHDRFile(const char *_fileName)
{
    FILE *file;
    file = osgDB::fopen(_fileName, "rb");
    if (!file)
        return false;

    char str[10];
    size_t numRead = fread(str, 10, 1, file);

    fclose(file);

    if (numRead<1) return false;

    if (memcmp(str, "#?RADIANCE", 10) && memcmp(str, "#?RGBE", 6))
        return false;

    return true;
}

bool HDRLoader::load(const char *_fileName, const bool _rawRGBE, HDRLoaderResult &_res)
{
    int i;
    char str[200];
    FILE *file;

    file = osgDB::fopen(_fileName, "rb");
    if (!file)
        return false;

    size_t numRead = fread(str, 10, 1, file);

    if (numRead<1)
    {
        fclose(file);
        return false;
    }

    if (memcmp(str, "#?RADIANCE", 10))
    {
        if (fseek(file, 0, SEEK_SET)!=0)
        {
            fclose(file);
            return false;
        }

        numRead = fread(str, 6, 1, file);
        if (numRead<1 || memcmp(str, "#?RGBE", 6))
        {
            fclose(file);
            return false;
        }
    }
    if (fseek(file, 1, SEEK_CUR)!=0)
    {
        fclose(file);
        return false;
    }

    //char cmd[2000];
    i = 0;
    char c = 0, oldc;
    int error = 0;
    while(!error) {
        oldc = c;
        c = read_char(file, error);
        if (c == 0xa && oldc == 0xa)
            break;
        //cmd[i++] = c;
    }

    char reso[2000];
    i = 0;
    while(!error) {
        c = read_char(file, error);
        reso[i++] = c;
        if (c == 0xa)
            break;
    }

    int w, h;
    if (!sscanf(reso, "-Y %d +X %d", &h, &w)) {
        fclose(file);
        return false;
    }

    _res.width = w;
    _res.height = h;

    int components = _rawRGBE ? 4 : 3;
    float *cols = new float[w * h * components];
    _res.cols = cols;

    RGBE *scanline = new RGBE[w];
    if (!scanline) {
        fclose(file);
        return false;
    }

    // convert image
    cols += (h-1) * w * components;
    for (int y = h - 1; y >= 0; y--) {
        if (decrunch(scanline, w, file) == false)
            break;
        if (_rawRGBE)
            rawRGBEData(scanline, w, cols);
        else
            workOnRGBE(scanline, w, cols);
        cols -= w * components;
    }

    delete [] scanline;
    fclose(file);

    return true;
}

void rawRGBEData(RGBE *_scan, int _len, float *_cols)
{
    int ii = 0;
    while (_len-- > 0) {
        _cols[0] = _scan[0][R] / 255.0f;
        _cols[1] = _scan[0][G] / 255.0f;
        _cols[2] = _scan[0][B] / 255.0f;
        _cols[3] = _scan[0][E] / 255.0f;
        _cols += 4;
        _scan++;
        ii++;
    }
}

inline float convertComponent(int _expo, int _val)
{
    return static_cast<float>(ldexp( static_cast<float>(_val), _expo-8));
}

void workOnRGBE(RGBE *_scan, int _len, float *_cols)
{
    int ii = 0;
    while (_len-- > 0) {
        int expo = _scan[0][E] - 128;
        _cols[0] = convertComponent(expo, _scan[0][R]);
        _cols[1] = convertComponent(expo, _scan[0][G]);
        _cols[2] = convertComponent(expo, _scan[0][B]);
        _cols += 3;
        _scan++;
        ii++;
    }
}

bool decrunch(RGBE *_scanline, int _len, FILE *_file)
{
    int  i, j;

    if (_len < MINELEN || _len > MAXELEN)
        return oldDecrunch(_scanline, _len, _file);

    i = fgetc(_file);
    if (i != 2) {
        if (fseek(_file, -1, SEEK_CUR)!=0)
        {
            return false;
        }
        return oldDecrunch(_scanline, _len, _file);
    }

    int error = 0;

    _scanline[0][G] = read_unsigned_char(_file, error);
    _scanline[0][B] = read_unsigned_char(_file, error);
    i = fgetc(_file);

    if (_scanline[0][G] != 2 || _scanline[0][B] & 128) {
        _scanline[0][R] = 2;
        _scanline[0][E] = i;
        return oldDecrunch(_scanline + 1, _len - 1, _file);
    }

    // read each component
    for (i = 0; i < 4; i++) {
        for (j = 0; j < _len; ) {
            unsigned char code = read_unsigned_char(_file, error);
            if (code > 128) { // run
                code &= 127;
                unsigned char val = read_unsigned_char(_file, error);
                while (code--)
                    _scanline[j++][i] = val;
            }
            else  {    // non-run
                while(code--)
                    _scanline[j++][i] = read_unsigned_char(_file, error);
            }
        }
    }

    return feof(_file) ? false : true;
}

bool oldDecrunch(RGBE *_scanline, int _len, FILE *_file)
{
    int i;
    int rshift = 0;

    int error = 0;

    while (_len > 0 && !error) {
        _scanline[0][R] = read_unsigned_char(_file, error);
        _scanline[0][G] = read_unsigned_char(_file, error);
        _scanline[0][B] = read_unsigned_char(_file, error);
        _scanline[0][E] = read_unsigned_char(_file, error);
        if (feof(_file))
            return false;

        if (_scanline[0][R] == 1 &&
            _scanline[0][G] == 1 &&
            _scanline[0][B] == 1) {
                for (i = _scanline[0][E] << rshift; i > 0; i--) {
                    memcpy(&_scanline[0][0], &_scanline[-1][0], 4);
                    _scanline++;
                    _len--;
                }
                rshift += 8;
            }
        else {
            _scanline++;
            _len--;
            rshift = 0;
        }
    }
    return true;
}
<|endoftext|>