<commit_before>/*
	Author: Brent Pease (embeddedlibraryfeedback@gmail.com)

	The MIT License (MIT)

	Copyright (c) 2015-FOREVER Brent Pease

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
	SOFTWARE.

	SFE_TSL2561 illumination sensor library for Arduino
	Mike Grusin, SparkFun Electronics

	This library provides functions to access the TAOS TSL2561
	Illumination Sensor.

	Our example code uses the "beerware" license. You can do anything
	you like with this code. No really, anything. If you find it useful,
	buy me a beer someday.

	version 1.0 2013/09/20 MDG initial version
	Updated to Arduino 1.6.4 5/2015

	Luminsoity sensor code included from Sparkfun's TSL2561 library to avoid requiring
	the user to download and install that library on their own.
*/
#include <EL.h>
#include <ELModule.h>
#include <ELUtilities.h>
#include <ELSerial.h>
#include <ELLuminositySensor.h>
#include <ELAssert.h>

enum ELuminositySensor
{
	eGain_1X = 0,
	eGain_16X = 1,

	eIntegrationTime_13_7ms = 0,
	eIntegrationTime_101ms = 1,
	eIntegrationTime_402ms = 2,
	eIntegrationTime_Manual = 3,

};

#define TSL2561_ADDR_0 0x29 // address with '0' shorted on board
#define TSL2561_ADDR   0x39 // default address
#define TSL2561_ADDR_1 0x49 // address with '1' shorted on board

// TSL2561 registers

#define TSL2561_CMD           0x80
#define TSL2561_CMD_CLEAR     0xC0
#define	TSL2561_REG_CONTROL   0x00
#define	TSL2561_REG_TIMING    0x01
#define	TSL2561_REG_THRESH_L  0x02
#define	TSL2561_REG_THRESH_H  0x04
#define	TSL2561_REG_INTCTL    0x06
#define	TSL2561_REG_ID        0x0A
#define	TSL2561_REG_DATA_0    0x0C
#define	TSL2561_REG_DATA_1    0x0E

CModule_LuminositySensor	CModule_LuminositySensor::module;
CModule_LuminositySensor*	gLuminositySensor;

CModule_LuminositySensor::CModule_LuminositySensor(
	)
	:
	CModule(
		"lumn",
		sizeof(SLuminositySettings),
		1,
		&settings,
		500000,
		1)
{
	gLuminositySensor = this;
}

float
CModule_LuminositySensor::GetActualLux(
	void)
{
	return (float)lux;
}

float
CModule_LuminositySensor::GetNormalizedBrightness(
	void)
{
	return (float)normalized;
}

void
CModule_LuminositySensor::SetMinMaxLux(
	float	inMinLux,
	float	inMaxLux,
	bool	inUpdateEEPROM)
{
	settings.minBrightnessLux = inMinLux;
	settings.maxBrightnessLux = inMaxLux;
	if(inUpdateEEPROM)
	{
		EEPROMSave();
	}
}

bool
CModule_LuminositySensor::SerialCmdGetLux(
	int			inArgC,
	char const*	inArgv[])
{
	DebugMsg(eDbgLevel_Basic, "lux = %f\n", GetActualLux());

	return true;
}

bool
CModule_LuminositySensor::SerialCmdConfig(
	int			inArgC,
	char const*	inArgv[])
{
	settings.gain = atoi(inArgv[1]);
	settings.time = atoi(inArgv[2]);
	EEPROMSave();

	SetupSensor();

	return true;
}

void
CModule_LuminositySensor::SetupSensor(
	void)
{
	switch (settings.time)
	{
		case 0: integrationTimeMS = 14; break;
		case 1: integrationTimeMS = 101; break;
		case 2: integrationTimeMS = 402; break;
		default: integrationTimeMS = 0;
	}

	// Turn off sensing to config
	WriteI2CByte(TSL2561_REG_CONTROL,0x00);

	// Get timing byte
	unsigned char timing;
	if(ReadI2CByte(TSL2561_REG_TIMING, timing))
	{
		// Set gain (0 or 1)
		if (settings.gain)
			timing |= 0x10;
		else
			timing &= ~0x10;

		// Set integration time (0 to 3)
		timing &= ~0x03;
		timing |= (settings.time & 0x03);

		// Write modified timing byte back to device
		WriteI2CByte(TSL2561_REG_TIMING,timing);
	}

	// Write 0x03 to command byte (power on)
	WriteI2CByte(TSL2561_REG_CONTROL,0x03);
}

void
CModule_LuminositySensor::Setup(
	void)
{
	return;

	_i2c_address = TSL2561_ADDR; // just assume default address for now
	Wire.begin();

	uint8_t	sensorID;
	bool	success;

	success = ReadI2CByte(TSL2561_REG_ID, sensorID);
	if(success == false || sensorID != 0x50)
	{
		SetEnabledState(false);
		return;
	}

	gSerialCmd->RegisterCommand("lumin_get_lux", this, static_cast<TSerialCmdMethod>(&CModule_LuminositySensor::SerialCmdGetLux));
	gSerialCmd->RegisterCommand("lumin_config", this, static_cast<TSerialCmdMethod>(&CModule_LuminositySensor::SerialCmdConfig));

	SetupSensor();
}

void
CModule_LuminositySensor::Update(
	uint32_t inDeltaTimeUS)
{
	return;

	uint16_t data0, data1;

	ReadI2CUInt16(TSL2561_REG_DATA_0, data0);
	ReadI2CUInt16(TSL2561_REG_DATA_1,data1);

	bool	good;

	good = GetLux(settings.gain, integrationTimeMS, data0, data1, lux);
	if(good)
	{
		double adjLux = lux;
		if(adjLux < settings.minBrightnessLux) adjLux = settings.minBrightnessLux;
		if(adjLux > settings.maxBrightnessLux) adjLux = settings.maxBrightnessLux;

		normalized = float((adjLux - settings.minBrightnessLux) / (settings.maxBrightnessLux - settings.minBrightnessLux));

		//Serial.printf("%f %f\n", lux, normalized);
	}
}

bool
CModule_LuminositySensor::GetLux(
	unsigned char	inGain,
	unsigned int	inMS,
	unsigned int	inCH0,
	unsigned int	inCH1,
	double&			outLux)
{
	// Convert raw data to lux
	// gain: 0 (1X) or 1 (16X), see setTiming()
	// ms: integration time in ms, from setTiming() or from manual integration
	// CH0, CH1: results from getData()
	// lux will be set to resulting lux calculation
	// returns true (1) if calculation was successful
	// RETURNS false (0) AND lux = 0.0 IF EITHER SENSOR WAS SATURATED (0XFFFF)

	double ratio, d0, d1;

	// Determine if either sensor saturated (0xFFFF)
	// If so, abandon ship (calculation will not be accurate)
	if ((inCH0 == 0xFFFF) || (inCH1 == 0xFFFF))
	{
		outLux = 0.0;
		return false;
	}

	// Convert from unsigned integer to floating point
	d0 = inCH0;
	d1 = inCH1;

	// We will need the ratio for subsequent calculations
	ratio = d1 / d0;

	// Normalize for integration time
	d0 *= (402.0/inMS);
	d1 *= (402.0/inMS);

	// Normalize for gain
	if (!inGain)
	{
		d0 *= 16;
		d1 *= 16;
	}

	// Determine lux per datasheet equations:

	if (ratio < 0.5)
	{
		outLux = 0.0304 * d0 - 0.062 * d0 * pow(ratio, 1.4);
		return true;
	}

	if (ratio < 0.61)
	{
		outLux = 0.0224 * d0 - 0.031 * d1;
		return true;
	}

	if (ratio < 0.80)
	{
		outLux = 0.0128 * d0 - 0.0153 * d1;
		return true;
	}

	if (ratio < 1.30)
	{
		outLux = 0.00146 * d0 - 0.00112 * d1;
		return true;
	}

	outLux = 0.0;

	return true;
}

bool
CModule_LuminositySensor::ReadI2CByte(
	uint8_t		inAddress,
	uint8_t&	outValue)
{
	// Reads a byte from a TSL2561 address
	// Address: TSL2561 address (0 to 15)
	// Value will be set to stored byte
	// Returns true (1) if successful, false (0) if there was an I2C error
	// (Also see getError() above)

	// Set up command byte for read
	Wire.beginTransmission(_i2c_address);
	Wire.write((inAddress & 0x0F) | TSL2561_CMD);
	_error = Wire.endTransmission();

	// Read requested byte
	if (_error == 0)
	{
		Wire.requestFrom(_i2c_address, 1);
		if (Wire.available() == 1)
		{
			outValue = Wire.read();
			return true;
		}
	}

	return false;
}

bool
CModule_LuminositySensor::WriteI2CByte(
	uint8_t	inAddress,
	uint8_t	inValue)
{
	// Write a byte to a TSL2561 address
	// Address: TSL2561 address (0 to 15)
	// Value: byte to write to address
	// Returns true (1) if successful, false (0) if there was an I2C error
	// (Also see getError() above)

	// Set up command byte for write
	Wire.beginTransmission(_i2c_address);
	Wire.write((inAddress & 0x0F) | TSL2561_CMD);
	// Write byte
	Wire.write(inValue);
	_error = Wire.endTransmission();

	return _error == 0;
}

bool
CModule_LuminositySensor::ReadI2CUInt16(
	uint8_t		inAddress,
	uint16_t&	outValue)
{
	// Reads an unsigned integer (16 bits) from a TSL2561 address (low byte first)
	// Address: TSL2561 address (0 to 15), low byte first
	// Value will be set to stored unsigned integer
	// Returns true (1) if successful, false (0) if there was an I2C error
	// (Also see getError() above)

	char high, low;

	// Set up command byte for read
	Wire.beginTransmission(_i2c_address);
	Wire.write((inAddress & 0x0F) | TSL2561_CMD);
	_error = Wire.endTransmission();

	// Read two bytes (low and high)
	if (_error == 0)
	{
		Wire.requestFrom(_i2c_address, 2);
		if (Wire.available() == 2)
		{
			low = Wire.read();
			high = Wire.read();
			// Combine bytes into unsigned int
			outValue = word(high,low);
			return true;
		}
	}

	return false;
}

bool
CModule_LuminositySensor::WriteI2CUInt16(
	uint8_t		inAddress,
	uint16_t	inValue)
{
	// Write an unsigned integer (16 bits) to a TSL2561 address (low byte first)
	// Address: TSL2561 address (0 to 15), low byte first
	// Value: unsigned int to write to address
	// Returns true (1) if successful, false (0) if there was an I2C error
	// (Also see getError() above)
	// Split int into lower and upper bytes, write each byte
	if (WriteI2CByte(inAddress, lowByte(inValue))
		&& WriteI2CByte(inAddress + 1, highByte(inValue)))
	{
		return true;
	}

	return false;
}
<commit_msg>Re-enable luminosity settings<commit_after>/*
	Author: Brent Pease (embeddedlibraryfeedback@gmail.com)

	The MIT License (MIT)

	Copyright (c) 2015-FOREVER Brent Pease

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
	SOFTWARE.

	SFE_TSL2561 illumination sensor library for Arduino
	Mike Grusin, SparkFun Electronics

	This library provides functions to access the TAOS TSL2561
	Illumination Sensor.

	Our example code uses the "beerware" license. You can do anything
	you like with this code. No really, anything. If you find it useful,
	buy me a beer someday.

	version 1.0 2013/09/20 MDG initial version
	Updated to Arduino 1.6.4 5/2015

	Luminsoity sensor code included from Sparkfun's TSL2561 library to avoid requiring
	the user to download and install that library on their own.
*/
#include <EL.h>
#include <ELModule.h>
#include <ELUtilities.h>
#include <ELSerial.h>
#include <ELLuminositySensor.h>
#include <ELAssert.h>

enum ELuminositySensor
{
	eGain_1X = 0,
	eGain_16X = 1,

	eIntegrationTime_13_7ms = 0,
	eIntegrationTime_101ms = 1,
	eIntegrationTime_402ms = 2,
	eIntegrationTime_Manual = 3,

};

#define TSL2561_ADDR_0 0x29 // address with '0' shorted on board
#define TSL2561_ADDR   0x39 // default address
#define TSL2561_ADDR_1 0x49 // address with '1' shorted on board

// TSL2561 registers

#define TSL2561_CMD           0x80
#define TSL2561_CMD_CLEAR     0xC0
#define	TSL2561_REG_CONTROL   0x00
#define	TSL2561_REG_TIMING    0x01
#define	TSL2561_REG_THRESH_L  0x02
#define	TSL2561_REG_THRESH_H  0x04
#define	TSL2561_REG_INTCTL    0x06
#define	TSL2561_REG_ID        0x0A
#define	TSL2561_REG_DATA_0    0x0C
#define	TSL2561_REG_DATA_1    0x0E

CModule_LuminositySensor	CModule_LuminositySensor::module;
CModule_LuminositySensor*	gLuminositySensor;

CModule_LuminositySensor::CModule_LuminositySensor(
	)
	:
	CModule(
		"lumn",
		sizeof(SLuminositySettings),
		1,
		&settings,
		500000,
		1)
{
	gLuminositySensor = this;
}

float
CModule_LuminositySensor::GetActualLux(
	void)
{
	return (float)lux;
}

float
CModule_LuminositySensor::GetNormalizedBrightness(
	void)
{
	return (float)normalized;
}

void
CModule_LuminositySensor::SetMinMaxLux(
	float	inMinLux,
	float	inMaxLux,
	bool	inUpdateEEPROM)
{
	settings.minBrightnessLux = inMinLux;
	settings.maxBrightnessLux = inMaxLux;
	if(inUpdateEEPROM)
	{
		EEPROMSave();
	}
}

bool
CModule_LuminositySensor::SerialCmdGetLux(
	int			inArgC,
	char const*	inArgv[])
{
	DebugMsg(eDbgLevel_Basic, "lux = %f\n", GetActualLux());

	return true;
}

bool
CModule_LuminositySensor::SerialCmdConfig(
	int			inArgC,
	char const*	inArgv[])
{
	settings.gain = atoi(inArgv[1]);
	settings.time = atoi(inArgv[2]);
	EEPROMSave();

	SetupSensor();

	return true;
}

void
CModule_LuminositySensor::SetupSensor(
	void)
{
	switch (settings.time)
	{
		case 0: integrationTimeMS = 14; break;
		case 1: integrationTimeMS = 101; break;
		case 2: integrationTimeMS = 402; break;
		default: integrationTimeMS = 0;
	}

	// Turn off sensing to config
	WriteI2CByte(TSL2561_REG_CONTROL,0x00);

	// Get timing byte
	unsigned char timing;
	if(ReadI2CByte(TSL2561_REG_TIMING, timing))
	{
		// Set gain (0 or 1)
		if (settings.gain)
			timing |= 0x10;
		else
			timing &= ~0x10;

		// Set integration time (0 to 3)
		timing &= ~0x03;
		timing |= (settings.time & 0x03);

		// Write modified timing byte back to device
		WriteI2CByte(TSL2561_REG_TIMING,timing);
	}

	// Write 0x03 to command byte (power on)
	WriteI2CByte(TSL2561_REG_CONTROL,0x03);
}

void
CModule_LuminositySensor::Setup(
	void)
{
	_i2c_address = TSL2561_ADDR; // just assume default address for now
	Wire.begin();

	uint8_t	sensorID;
	bool	success;

	success = ReadI2CByte(TSL2561_REG_ID, sensorID);
	if(success == false || sensorID != 0x50)
	{
		SetEnabledState(false);
		return;
	}

	gSerialCmd->RegisterCommand("lumin_get_lux", this, static_cast<TSerialCmdMethod>(&CModule_LuminositySensor::SerialCmdGetLux));
	gSerialCmd->RegisterCommand("lumin_config", this, static_cast<TSerialCmdMethod>(&CModule_LuminositySensor::SerialCmdConfig));

	SetupSensor();
}

void
CModule_LuminositySensor::Update(
	uint32_t inDeltaTimeUS)
{

	uint16_t data0, data1;

	ReadI2CUInt16(TSL2561_REG_DATA_0, data0);
	ReadI2CUInt16(TSL2561_REG_DATA_1,data1);

	bool	good;

	good = GetLux(settings.gain, integrationTimeMS, data0, data1, lux);
	if(good)
	{
		double adjLux = lux;
		if(adjLux < settings.minBrightnessLux) adjLux = settings.minBrightnessLux;
		if(adjLux > settings.maxBrightnessLux) adjLux = settings.maxBrightnessLux;

		normalized = float((adjLux - settings.minBrightnessLux) / (settings.maxBrightnessLux - settings.minBrightnessLux));

		//Serial.printf("%f %f\n", lux, normalized);
	}
}

bool
CModule_LuminositySensor::GetLux(
	unsigned char	inGain,
	unsigned int	inMS,
	unsigned int	inCH0,
	unsigned int	inCH1,
	double&			outLux)
{
	// Convert raw data to lux
	// gain: 0 (1X) or 1 (16X), see setTiming()
	// ms: integration time in ms, from setTiming() or from manual integration
	// CH0, CH1: results from getData()
	// lux will be set to resulting lux calculation
	// returns true (1) if calculation was successful
	// RETURNS false (0) AND lux = 0.0 IF EITHER SENSOR WAS SATURATED (0XFFFF)

	double ratio, d0, d1;

	// Determine if either sensor saturated (0xFFFF)
	// If so, abandon ship (calculation will not be accurate)
	if ((inCH0 == 0xFFFF) || (inCH1 == 0xFFFF))
	{
		outLux = 0.0;
		return false;
	}

	// Convert from unsigned integer to floating point
	d0 = inCH0;
	d1 = inCH1;

	// We will need the ratio for subsequent calculations
	ratio = d1 / d0;

	// Normalize for integration time
	d0 *= (402.0/inMS);
	d1 *= (402.0/inMS);

	// Normalize for gain
	if (!inGain)
	{
		d0 *= 16;
		d1 *= 16;
	}

	// Determine lux per datasheet equations:

	if (ratio < 0.5)
	{
		outLux = 0.0304 * d0 - 0.062 * d0 * pow(ratio, 1.4);
		return true;
	}

	if (ratio < 0.61)
	{
		outLux = 0.0224 * d0 - 0.031 * d1;
		return true;
	}

	if (ratio < 0.80)
	{
		outLux = 0.0128 * d0 - 0.0153 * d1;
		return true;
	}

	if (ratio < 1.30)
	{
		outLux = 0.00146 * d0 - 0.00112 * d1;
		return true;
	}

	outLux = 0.0;

	return true;
}

bool
CModule_LuminositySensor::ReadI2CByte(
	uint8_t		inAddress,
	uint8_t&	outValue)
{
	// Reads a byte from a TSL2561 address
	// Address: TSL2561 address (0 to 15)
	// Value will be set to stored byte
	// Returns true (1) if successful, false (0) if there was an I2C error
	// (Also see getError() above)

	// Set up command byte for read
	Wire.beginTransmission(_i2c_address);
	Wire.write((inAddress & 0x0F) | TSL2561_CMD);
	_error = Wire.endTransmission();

	// Read requested byte
	if (_error == 0)
	{
		Wire.requestFrom(_i2c_address, 1);
		if (Wire.available() == 1)
		{
			outValue = Wire.read();
			return true;
		}
	}

	return false;
}

bool
CModule_LuminositySensor::WriteI2CByte(
	uint8_t	inAddress,
	uint8_t	inValue)
{
	// Write a byte to a TSL2561 address
	// Address: TSL2561 address (0 to 15)
	// Value: byte to write to address
	// Returns true (1) if successful, false (0) if there was an I2C error
	// (Also see getError() above)

	// Set up command byte for write
	Wire.beginTransmission(_i2c_address);
	Wire.write((inAddress & 0x0F) | TSL2561_CMD);
	// Write byte
	Wire.write(inValue);
	_error = Wire.endTransmission();

	return _error == 0;
}

bool
CModule_LuminositySensor::ReadI2CUInt16(
	uint8_t		inAddress,
	uint16_t&	outValue)
{
	// Reads an unsigned integer (16 bits) from a TSL2561 address (low byte first)
	// Address: TSL2561 address (0 to 15), low byte first
	// Value will be set to stored unsigned integer
	// Returns true (1) if successful, false (0) if there was an I2C error
	// (Also see getError() above)

	char high, low;

	// Set up command byte for read
	Wire.beginTransmission(_i2c_address);
	Wire.write((inAddress & 0x0F) | TSL2561_CMD);
	_error = Wire.endTransmission();

	// Read two bytes (low and high)
	if (_error == 0)
	{
		Wire.requestFrom(_i2c_address, 2);
		if (Wire.available() == 2)
		{
			low = Wire.read();
			high = Wire.read();
			// Combine bytes into unsigned int
			outValue = word(high,low);
			return true;
		}
	}

	return false;
}

bool
CModule_LuminositySensor::WriteI2CUInt16(
	uint8_t		inAddress,
	uint16_t	inValue)
{
	// Write an unsigned integer (16 bits) to a TSL2561 address (low byte first)
	// Address: TSL2561 address (0 to 15), low byte first
	// Value: unsigned int to write to address
	// Returns true (1) if successful, false (0) if there was an I2C error
	// (Also see getError() above)
	// Split int into lower and upper bytes, write each byte
	if (WriteI2CByte(inAddress, lowByte(inValue))
		&& WriteI2CByte(inAddress + 1, highByte(inValue)))
	{
		return true;
	}

	return false;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
#include <RX.h>
#include <Context.h>
#include <i18n.h>
#include <text.h>
#include <util.h>
#ifdef HAVE_COMMIT
#include <commit.h>
#endif

#ifdef HAVE_LIBGNUTLS
#include <gnutls/gnutls.h>
#endif

#include <CmdDiagnostics.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
CmdDiagnostics::CmdDiagnostics ()
{
  _keyword     = "diagnostics";
  _usage       = "task          diagnostics";
  _description = STRING_CMD_DIAG_USAGE;
  _read_only   = true;
  _displays_id = false;
}

////////////////////////////////////////////////////////////////////////////////
// This command will generate output that is intended to help diagnose problems.
//
// Although this will change over time, initially this command will answer the
// kind of questions we always have to ask whenever something is wrong.
int CmdDiagnostics::execute (std::string& output)
{
  Color bold;
  if (context.color ())
    bold = Color ("bold");

  std::stringstream out;
  out << "\n"
      << bold.colorize (PACKAGE_STRING)
      << "\n";

  out << "   " << STRING_CMD_DIAG_PLATFORM << ": "
      <<
#if defined (DARWIN)
         "Darwin"
#elif defined (SOLARIS)
         "Solaris"
#elif defined (CYGWIN)
         "Cygwin"
#elif defined (HAIKU)
         "Haiku"
#elif defined (OPENBSD)
         "OpenBSD"
#elif defined (FREEBSD)
         "FreeBSD"
#elif defined (NETBSD)
         "NetBSD"
#elif defined (LINUX)
         "Linux"
#elif defined (KFREEBSD)
         "GNU/kFreeBSD"
#elif defined (GNUHURD)
         "GNU/Hurd"
#else
         STRING_CMD_DIAG_UNKNOWN
#endif
      << "\n\n";

  // Compiler.
  out << bold.colorize (STRING_CMD_DIAG_COMPILER)
      << "\n"
#ifdef __VERSION__
      << "    " << STRING_CMD_DIAG_VERSION << ": "
      << __VERSION__ << "\n"
#endif
      << "       " << STRING_CMD_DIAG_CAPS << ":"
#ifdef __STDC__
      << " +stdc"
#endif
#ifdef __STDC_HOSTED__
      << " +stdc_hosted"
#endif
#ifdef __STDC_VERSION__
      << " +" << __STDC_VERSION__
#endif
#ifdef _POSIX_VERSION
      << " +" << _POSIX_VERSION
#endif
#ifdef _POSIX2_C_VERSION
      << " +" << _POSIX2_C_VERSION
#endif
#ifdef _ILP32
      << " +ILP32"
#endif
#ifdef _LP64
      << " +LP64"
#endif
      << " +c"      << 8 * sizeof (char)
      << " +i"      << 8 * sizeof (int)
      << " +l"      << 8 * sizeof (long)
      << " +vp"     << 8 * sizeof (void*)
      << " +time_t" << 8 * sizeof (time_t)
      << "\n";

  // Compiler compliance level.
  std::string compliance = "non-compliant";
#ifdef __cplusplus
  int level = __cplusplus;
  if (level == 199711)
    compliance = "C++98/03";
  else if (level == 201103)
    compliance = "C++11";
  else
    compliance = format (level);
#endif
  out << " " << STRING_CMD_DIAG_COMPLIANCE
      << ": "
      << compliance
      << "\n\n";

  out << bold.colorize (STRING_CMD_DIAG_FEATURES)
      << "\n"

  // Build date.
      << "      " << STRING_CMD_DIAG_BUILT << ": " << __DATE__ << " " << __TIME__ << "\n"
#ifdef HAVE_COMMIT
      << "     " << STRING_CMD_DIAG_COMMIT << ": " << COMMIT << "\n"
#endif
      << "      CMake: " << CMAKE_VERSION << "\n"
      << "       " << STRING_CMD_DIAG_CAPS << ":"
#ifdef HAVE_LIBGNUTLS
      << " +tls"
#else
      << " -tls"
#endif
      << "\n";

  out << "    libuuid: "
#ifdef HAVE_UUID_UNPARSE_LOWER
      << "libuuid + uuid_unparse_lower"
#else
      << "libuuid, no uuid_unparse_lower"
#endif
      << "\n";

  out << "  libgnutls: "
#ifdef HAVE_LIBGNUTLS
#ifdef GNUTLS_VERSION
      << GNUTLS_VERSION
#elif defined LIBGNUTLS_VERSION
      << LIBGNUTLS_VERSION
#endif
#else
      << "n/a"
#endif
      << "\n";

  out << " Build type: "
#ifdef CMAKE_BUILD_TYPE
      << CMAKE_BUILD_TYPE
#else
      << "-"
#endif
      << "\n\n";

  // Config: .taskrc found, readable, writable
  out << bold.colorize (STRING_CMD_DIAG_CONFIG)
      << "\n"
      << "       File: " << context.config._original_file._data << " "
      << (context.config._original_file.exists ()
           ? STRING_CMD_DIAG_FOUND
           : STRING_CMD_DIAG_MISSING)
      << ", " << context.config._original_file.size () << " " << "bytes"
      << ", mode "
      << std::setbase (8)
      << context.config._original_file.mode ()
      << "\n";

  // Config: data.location found, readable, writable
  File location (context.config.get ("data.location"));
  out << "       Data: " << location._data << " "
      << (location.exists ()
           ? STRING_CMD_DIAG_FOUND
           : STRING_CMD_DIAG_MISSING)
      << ", " << (location.is_directory () ? "dir" : "?")
      << ", mode "
      << std::setbase (8)
      << location.mode ()
      << "\n";

  char* env = getenv ("TASKRC");
  if (env)
    out << "     TASKRC: "
        << env
        << "\n";

  env = getenv ("TASKDATA");
  if (env)
    out << "   TASKDATA: "
        << env
        << "\n";

  out << "    Locking: "
      << (context.config.getBoolean ("locking")
           ? STRING_CMD_DIAG_ENABLED
           : STRING_CMD_DIAG_DISABLED)
      << "\n";

  out << "         GC: "
      << (context.config.getBoolean ("gc")
           ? STRING_CMD_DIAG_ENABLED
           : STRING_CMD_DIAG_DISABLED)
      << "\n";

  // Determine rc.editor/$EDITOR/$VISUAL.
  char* peditor;
  if (context.config.get ("editor") != "")
    out << "  rc.editor: " << context.config.get ("editor") << "\n";
  else if ((peditor = getenv ("VISUAL")) != NULL)
    out << "    $VISUAL: " << peditor << "\n";
  else if ((peditor = getenv ("EDITOR")) != NULL)
    out << "    $EDITOR: " << peditor << "\n";

  out << "     Server: "
      << context.config.get ("taskd.server")
      << "\n";

  if (context.config.get ("taskd.ca") != "")
    out << "         CA: "
        << context.config.get ("taskd.ca")
        << (File (context.config.get ("taskd.ca")).readable ()
             ? " (readable)" : " (not readable)")
        << "\n";

  std::string trust_value = context.config.get ("taskd.trust");
  if (trust_value == "strict" ||
      trust_value == "ignore hostname" ||
      trust_value == "allow all")
    out << "      Trust: " << trust_value << "\n";
  else
    out << "      Trust: Bad value - see 'man taskrc'\n";

  out << "Certificate: "
      << context.config.get ("taskd.certificate")
      << (File (context.config.get ("taskd.certificate")).readable ()
           ? " (readable)" : " (not readable)")
      << "\n";

  out << "        Key: "
      << context.config.get ("taskd.key")
      << (File (context.config.get ("taskd.key")).readable ()
           ? " (readable)" : " (not readable)")
      << "\n";

  out << "    Ciphers: "
      << context.config.get ("taskd.ciphers")
      << "\n";

  // Get credentials, but mask out the key.
  std::string credentials = context.config.get ("taskd.credentials");
  std::string::size_type last_slash = credentials.rfind ('/');
  if (last_slash != std::string::npos)
    credentials = credentials.substr (0, last_slash)
                + "/"
                + std::string (credentials.length () - last_slash - 1, '*');

  out << "      Creds: "
      << credentials
      << "\n\n";

  // Disaply hook status.
  out << bold.colorize (STRING_CMD_DIAG_HOOKS)
      << "\n"
      << "    Scripts: "
      << (context.config.getBoolean ("hooks") ? STRING_CMD_DIAG_HOOK_ENABLE : STRING_CMD_DIAG_HOOK_DISABLE)
      << "\n";

  std::vector <std::string> hooks = context.hooks.list ();
  if (hooks.size ())
  {
    std::vector <std::string>::iterator h;
    for (h = hooks.begin (); h != hooks.end (); ++h)
    {
      Path p (*h);
      std::string name = p.name ();
      out << "             "
          << *h
          << (p.executable () ? format (" ({1})", STRING_CMD_DIAG_HOOK_EXEC) : format (" ({1})", STRING_CMD_DIAG_HOOK_NO_EXEC))
          << (p.is_link () ? format (" ({1})", STRING_CMD_DIAG_HOOK_SYMLINK) : "")
          << ((name.substr (0, 6) == "on-add" ||
               name.substr (0, 9) == "on-modify" ||
               name.substr (0, 9) == "on-launch" ||
               name.substr (0, 7) == "on-exit") ? "" : format (" ({1})", STRING_CMD_DIAG_HOOK_NAME))
          << "\n";
    }
  }
  else
    out << format ("             ({1})\n", STRING_CMD_DIAG_NONE);

  out << "\n";

  // Verify UUIDs are all unique.
  out << bold.colorize (STRING_CMD_DIAG_TESTS)
      << "\n";
  {
    // Determine terminal details.
    const char* term = getenv ("TERM");
    out << "      $TERM: "
        << (term ? term : STRING_CMD_DIAG_NONE)
        << " ("
        << context.getWidth ()
        << "x"
        << context.getHeight ()
        << ")\n";

    // Scan tasks for duplicate UUIDs.
    std::vector <Task> all = context.tdb2.all_tasks ();
    std::map <std::string, int> seen;
    std::vector <std::string> dups;
    std::string uuid;
    std::vector <Task>::iterator i;
    for (i = all.begin (); i != all.end (); ++i)
    {
      uuid = i->get ("uuid");
      if (seen.find (uuid) != seen.end ())
        dups.push_back (uuid);
      else
         seen[uuid] = 0;
    }

    out << "       Dups: "
        << format (STRING_CMD_DIAG_UUID_SCAN, all.size ())
        << "\n";

    if (dups.size ())
    {
      std::vector <std::string>::iterator d;
      for (d = dups.begin (); d != dups.end (); ++d)
        out << "             " << format (STRING_CMD_DIAG_UUID_DUP, *d) << "\n";
    }
    else
    {
      out << "             " << STRING_CMD_DIAG_UUID_NO_DUP
          << "\n";
    }
  }

  out << "\n";
  output = out.str ();
  return 0;
}

////////////////////////////////////////////////////////////////////////////////
<commit_msg>Diagnostics: Removed 'Build caps' line<commit_after>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
#include <RX.h>
#include <Context.h>
#include <i18n.h>
#include <text.h>
#include <util.h>
#ifdef HAVE_COMMIT
#include <commit.h>
#endif

#ifdef HAVE_LIBGNUTLS
#include <gnutls/gnutls.h>
#endif

#include <CmdDiagnostics.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
CmdDiagnostics::CmdDiagnostics ()
{
  _keyword     = "diagnostics";
  _usage       = "task          diagnostics";
  _description = STRING_CMD_DIAG_USAGE;
  _read_only   = true;
  _displays_id = false;
}

////////////////////////////////////////////////////////////////////////////////
// This command will generate output that is intended to help diagnose problems.
//
// Although this will change over time, initially this command will answer the
// kind of questions we always have to ask whenever something is wrong.
int CmdDiagnostics::execute (std::string& output)
{
  Color bold;
  if (context.color ())
    bold = Color ("bold");

  std::stringstream out;
  out << "\n"
      << bold.colorize (PACKAGE_STRING)
      << "\n";

  out << "   " << STRING_CMD_DIAG_PLATFORM << ": "
      <<
#if defined (DARWIN)
         "Darwin"
#elif defined (SOLARIS)
         "Solaris"
#elif defined (CYGWIN)
         "Cygwin"
#elif defined (HAIKU)
         "Haiku"
#elif defined (OPENBSD)
         "OpenBSD"
#elif defined (FREEBSD)
         "FreeBSD"
#elif defined (NETBSD)
         "NetBSD"
#elif defined (LINUX)
         "Linux"
#elif defined (KFREEBSD)
         "GNU/kFreeBSD"
#elif defined (GNUHURD)
         "GNU/Hurd"
#else
         STRING_CMD_DIAG_UNKNOWN
#endif
      << "\n\n";

  // Compiler.
  out << bold.colorize (STRING_CMD_DIAG_COMPILER)
      << "\n"
#ifdef __VERSION__
      << "    " << STRING_CMD_DIAG_VERSION << ": "
      << __VERSION__ << "\n"
#endif
      << "       " << STRING_CMD_DIAG_CAPS << ":"
#ifdef __STDC__
      << " +stdc"
#endif
#ifdef __STDC_HOSTED__
      << " +stdc_hosted"
#endif
#ifdef __STDC_VERSION__
      << " +" << __STDC_VERSION__
#endif
#ifdef _POSIX_VERSION
      << " +" << _POSIX_VERSION
#endif
#ifdef _POSIX2_C_VERSION
      << " +" << _POSIX2_C_VERSION
#endif
#ifdef _ILP32
      << " +ILP32"
#endif
#ifdef _LP64
      << " +LP64"
#endif
      << " +c"      << 8 * sizeof (char)
      << " +i"      << 8 * sizeof (int)
      << " +l"      << 8 * sizeof (long)
      << " +vp"     << 8 * sizeof (void*)
      << " +time_t" << 8 * sizeof (time_t)
      << "\n";

  // Compiler compliance level.
  std::string compliance = "non-compliant";
#ifdef __cplusplus
  int level = __cplusplus;
  if (level == 199711)
    compliance = "C++98/03";
  else if (level == 201103)
    compliance = "C++11";
  else
    compliance = format (level);
#endif
  out << " " << STRING_CMD_DIAG_COMPLIANCE
      << ": "
      << compliance
      << "\n\n";

  out << bold.colorize (STRING_CMD_DIAG_FEATURES)
      << "\n"

  // Build date.
      << "      " << STRING_CMD_DIAG_BUILT << ": " << __DATE__ << " " << __TIME__ << "\n"
#ifdef HAVE_COMMIT
      << "     " << STRING_CMD_DIAG_COMMIT << ": " << COMMIT << "\n"
#endif
      << "      CMake: " << CMAKE_VERSION << "\n";

  out << "    libuuid: "
#ifdef HAVE_UUID_UNPARSE_LOWER
      << "libuuid + uuid_unparse_lower"
#else
      << "libuuid, no uuid_unparse_lower"
#endif
      << "\n";

  out << "  libgnutls: "
#ifdef HAVE_LIBGNUTLS
#ifdef GNUTLS_VERSION
      << GNUTLS_VERSION
#elif defined LIBGNUTLS_VERSION
      << LIBGNUTLS_VERSION
#endif
#else
      << "n/a"
#endif
      << "\n";

  out << " Build type: "
#ifdef CMAKE_BUILD_TYPE
      << CMAKE_BUILD_TYPE
#else
      << "-"
#endif
      << "\n\n";

  // Config: .taskrc found, readable, writable
  out << bold.colorize (STRING_CMD_DIAG_CONFIG)
      << "\n"
      << "       File: " << context.config._original_file._data << " "
      << (context.config._original_file.exists ()
           ? STRING_CMD_DIAG_FOUND
           : STRING_CMD_DIAG_MISSING)
      << ", " << context.config._original_file.size () << " " << "bytes"
      << ", mode "
      << std::setbase (8)
      << context.config._original_file.mode ()
      << "\n";

  // Config: data.location found, readable, writable
  File location (context.config.get ("data.location"));
  out << "       Data: " << location._data << " "
      << (location.exists ()
           ? STRING_CMD_DIAG_FOUND
           : STRING_CMD_DIAG_MISSING)
      << ", " << (location.is_directory () ? "dir" : "?")
      << ", mode "
      << std::setbase (8)
      << location.mode ()
      << "\n";

  char* env = getenv ("TASKRC");
  if (env)
    out << "     TASKRC: "
        << env
        << "\n";

  env = getenv ("TASKDATA");
  if (env)
    out << "   TASKDATA: "
        << env
        << "\n";

  out << "    Locking: "
      << (context.config.getBoolean ("locking")
           ? STRING_CMD_DIAG_ENABLED
           : STRING_CMD_DIAG_DISABLED)
      << "\n";

  out << "         GC: "
      << (context.config.getBoolean ("gc")
           ? STRING_CMD_DIAG_ENABLED
           : STRING_CMD_DIAG_DISABLED)
      << "\n";

  // Determine rc.editor/$EDITOR/$VISUAL.
  char* peditor;
  if (context.config.get ("editor") != "")
    out << "  rc.editor: " << context.config.get ("editor") << "\n";
  else if ((peditor = getenv ("VISUAL")) != NULL)
    out << "    $VISUAL: " << peditor << "\n";
  else if ((peditor = getenv ("EDITOR")) != NULL)
    out << "    $EDITOR: " << peditor << "\n";

  out << "     Server: "
      << context.config.get ("taskd.server")
      << "\n";

  if (context.config.get ("taskd.ca") != "")
    out << "         CA: "
        << context.config.get ("taskd.ca")
        << (File (context.config.get ("taskd.ca")).readable ()
             ? " (readable)" : " (not readable)")
        << "\n";

  std::string trust_value = context.config.get ("taskd.trust");
  if (trust_value == "strict" ||
      trust_value == "ignore hostname" ||
      trust_value == "allow all")
    out << "      Trust: " << trust_value << "\n";
  else
    out << "      Trust: Bad value - see 'man taskrc'\n";

  out << "Certificate: "
      << context.config.get ("taskd.certificate")
      << (File (context.config.get ("taskd.certificate")).readable ()
           ? " (readable)" : " (not readable)")
      << "\n";

  out << "        Key: "
      << context.config.get ("taskd.key")
      << (File (context.config.get ("taskd.key")).readable ()
           ? " (readable)" : " (not readable)")
      << "\n";

  out << "    Ciphers: "
      << context.config.get ("taskd.ciphers")
      << "\n";

  // Get credentials, but mask out the key.
  std::string credentials = context.config.get ("taskd.credentials");
  std::string::size_type last_slash = credentials.rfind ('/');
  if (last_slash != std::string::npos)
    credentials = credentials.substr (0, last_slash)
                + "/"
                + std::string (credentials.length () - last_slash - 1, '*');

  out << "      Creds: "
      << credentials
      << "\n\n";

  // Disaply hook status.
  out << bold.colorize (STRING_CMD_DIAG_HOOKS)
      << "\n"
      << "    Scripts: "
      << (context.config.getBoolean ("hooks") ? STRING_CMD_DIAG_HOOK_ENABLE : STRING_CMD_DIAG_HOOK_DISABLE)
      << "\n";

  std::vector <std::string> hooks = context.hooks.list ();
  if (hooks.size ())
  {
    std::vector <std::string>::iterator h;
    for (h = hooks.begin (); h != hooks.end (); ++h)
    {
      Path p (*h);
      std::string name = p.name ();
      out << "             "
          << *h
          << (p.executable () ? format (" ({1})", STRING_CMD_DIAG_HOOK_EXEC) : format (" ({1})", STRING_CMD_DIAG_HOOK_NO_EXEC))
          << (p.is_link () ? format (" ({1})", STRING_CMD_DIAG_HOOK_SYMLINK) : "")
          << ((name.substr (0, 6) == "on-add" ||
               name.substr (0, 9) == "on-modify" ||
               name.substr (0, 9) == "on-launch" ||
               name.substr (0, 7) == "on-exit") ? "" : format (" ({1})", STRING_CMD_DIAG_HOOK_NAME))
          << "\n";
    }
  }
  else
    out << format ("             ({1})\n", STRING_CMD_DIAG_NONE);

  out << "\n";

  // Verify UUIDs are all unique.
  out << bold.colorize (STRING_CMD_DIAG_TESTS)
      << "\n";
  {
    // Determine terminal details.
    const char* term = getenv ("TERM");
    out << "      $TERM: "
        << (term ? term : STRING_CMD_DIAG_NONE)
        << " ("
        << context.getWidth ()
        << "x"
        << context.getHeight ()
        << ")\n";

    // Scan tasks for duplicate UUIDs.
    std::vector <Task> all = context.tdb2.all_tasks ();
    std::map <std::string, int> seen;
    std::vector <std::string> dups;
    std::string uuid;
    std::vector <Task>::iterator i;
    for (i = all.begin (); i != all.end (); ++i)
    {
      uuid = i->get ("uuid");
      if (seen.find (uuid) != seen.end ())
        dups.push_back (uuid);
      else
         seen[uuid] = 0;
    }

    out << "       Dups: "
        << format (STRING_CMD_DIAG_UUID_SCAN, all.size ())
        << "\n";

    if (dups.size ())
    {
      std::vector <std::string>::iterator d;
      for (d = dups.begin (); d != dups.end (); ++d)
        out << "             " << format (STRING_CMD_DIAG_UUID_DUP, *d) << "\n";
    }
    else
    {
      out << "             " << STRING_CMD_DIAG_UUID_NO_DUP
          << "\n";
    }
  }

  out << "\n";
  output = out.str ();
  return 0;
}

////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Authors: Mark Young <marky@lunarg.com>
//          Nat Brown <natb@valvesoftware.com>
//

#include <cstring>
#include "xr_dependencies.h"

#if defined DISABLE_STD_FILESYSTEM
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 0

#else
// If the C++ macro is set to the version containing C++17, it must support
// the final C++17 package
#if __cplusplus >= 201703L
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1

#elif defined(_MSC_VER) && _MSC_VER >= 1900

#if defined(_HAS_CXX17) && _HAS_CXX17
// When MSC supports c++17 use <filesystem> package.
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#else
// MSC before c++17 need to use <experimental/filesystem> package.
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0
#endif  // !_HAS_CXX17

// Right now, GCC still only supports the experimental filesystem items starting in GCC 6
#elif (__GNUC__ >= 6)
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0

// If Clang, check for feature support
#elif defined(__clang__) && (__cpp_lib_filesystem || __cpp_lib_experimental_filesystem)
#if __cpp_lib_filesystem
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#else
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0
#endif

// If all above fails, fall back to standard C++ and OS-specific items
#else
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 0
#endif
#endif

#if USE_FINAL_FS == 1
#include <filesystem>
#define FS_PREFIX std::filesystem
#elif USE_EXPERIMENTAL_FS == 1
#if (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
#error "Windows universal application doesn't support system::experimental::filesystem"
#endif
#include <experimental/filesystem>
#define FS_PREFIX std::experimental::filesystem
#elif defined(XR_USE_PLATFORM_WIN32)
// Windows fallback includes
#include <stdint.h>
#include <direct.h>
#include <shlwapi.h>
#else
// Linux/Apple fallback includes
#include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <dirent.h>
#endif

#include "filesystem_utils.hpp"

#if defined(XR_USE_PLATFORM_WIN32)
#define PATH_SEPARATOR ';'
#define DIRECTORY_SYMBOL '\\'
#else
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
#endif

#if (USE_FINAL_FS == 1) || (USE_EXPERIMENTAL_FS == 1)
// We can use one of the C++ filesystem packages

bool FileSysUtilsIsRegularFile(const std::string& path) {
    try {
        return FS_PREFIX::is_regular_file(path);
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsDirectory(const std::string& path) {
    try {
        return FS_PREFIX::is_directory(path);
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsPathExists(const std::string& path) {
    try {
        return FS_PREFIX::exists(path);
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsAbsolutePath(const std::string& path) {
    try {
        FS_PREFIX::path file_path(path);
        return file_path.is_absolute();
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsGetCurrentPath(std::string& path) {
    try {
        FS_PREFIX::path cur_path = FS_PREFIX::current_path();
        path = cur_path.string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
    try {
        FS_PREFIX::path path_var(file_path);
        parent_path = path_var.parent_path().string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
    try {
        absolute = FS_PREFIX::absolute(path).string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
    try {
        FS_PREFIX::path parent_path(parent);
        FS_PREFIX::path child_path(child);
        FS_PREFIX::path full_path = parent_path / child_path;
        combined = full_path.string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
    try {
        std::string::size_type start = 0;
        std::string::size_type location = path_list.find(PATH_SEPARATOR);
        while (location != std::string::npos) {
            paths.push_back(path_list.substr(start, location));
            start = location + 1;
            location = path_list.find(PATH_SEPARATOR, start);
        }
        paths.push_back(path_list.substr(start, location));
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
    try {
        for (auto& dir_iter : FS_PREFIX::directory_iterator(path)) {
            files.push_back(dir_iter.path().filename().string());
        }
        return true;
    } catch (...) {
    }
    return false;
}

#elif defined(XR_OS_WINDOWS)

// Workaround for MS VS 2010/2013 don't support the experimental filesystem

bool FileSysUtilsIsRegularFile(const std::string& path) {
    try {
        return (1 != PathIsDirectoryA(path.c_str()));
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsDirectory(const std::string& path) {
    try {
        return (1 == PathIsDirectoryA(path.c_str()));
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsPathExists(const std::string& path) {
    try {
        return (1 == PathFileExistsA(path.c_str()));
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsAbsolutePath(const std::string& path) {
    try {
        if ((path[0] == '\\') || (path[1] == ':' && (path[2] == '\\' || path[2] == '/'))) {
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetCurrentPath(std::string& path) {
    try {
        char tmp_path[MAX_PATH];
        if (nullptr != _getcwd(tmp_path, MAX_PATH - 1)) {
            path = tmp_path;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
    try {
        std::string full_path;
        if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
            std::string::size_type lastSeperator = full_path.find_last_of(DIRECTORY_SYMBOL);
            parent_path = (lastSeperator == 0) ? full_path : full_path.substr(0, lastSeperator - 1);
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
    try {
        char tmp_path[MAX_PATH];
        if (0 != GetFullPathNameA(path.c_str(), MAX_PATH, tmp_path, NULL)) {
            absolute = tmp_path;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
    try {
        std::string::size_type parent_len = parent.length();
        if (0 == parent_len || "." == parent || ".\\" == parent || "./" == parent) {
            combined = child;
            return true;
        }
        char last_char = parent[parent_len - 1];
        if (last_char == DIRECTORY_SYMBOL) {
            parent_len--;
        }
        combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
    try {
        std::string::size_type start = 0;
        std::string::size_type location = path_list.find(PATH_SEPARATOR);
        while (location != std::string::npos) {
            paths.push_back(path_list.substr(start, location));
            start = location + 1;
            location = path_list.find(PATH_SEPARATOR, start);
        }
        paths.push_back(path_list.substr(start, location));
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
    try {
        WIN32_FIND_DATAA file_data;
        HANDLE file_handle = FindFirstFileA(path.c_str(), &file_data);
        if (file_handle != INVALID_HANDLE_VALUE) {
            do {
                if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
                    files.push_back(file_data.cFileName);
                }
            } while (FindNextFileA(file_handle, &file_data));
            return true;
        }
    } catch (...) {
    }
    return false;
}

#else  // XR_OS_LINUX/XR_OS_APPLE fallback

#include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>

// simple POSIX-compatible implementation of the <filesystem> pieces used by OpenXR

bool FileSysUtilsIsRegularFile(const std::string& path) {
    try {
        struct stat path_stat;
        stat(path.c_str(), &path_stat);
        return S_ISREG(path_stat.st_mode);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsIsDirectory(const std::string& path) {
    try {
        struct stat path_stat;
        stat(path.c_str(), &path_stat);
        return S_ISDIR(path_stat.st_mode);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsPathExists(const std::string& path) {
    try {
        return (access(path.c_str(), F_OK) != -1);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsIsAbsolutePath(const std::string& path) {
    try {
        return (path[0] == DIRECTORY_SYMBOL);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetCurrentPath(std::string& path) {
    try {
        char tmp_path[PATH_MAX];
        if (nullptr != getcwd(tmp_path, PATH_MAX - 1)) {
            path = tmp_path;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
    try {
        std::string full_path;
        if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
            std::string::size_type lastSeperator = full_path.find_last_of(DIRECTORY_SYMBOL);
            parent_path = (lastSeperator == 0) ? full_path : full_path.substr(0, lastSeperator - 1);
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
    try {
        char buf[PATH_MAX];
        if (nullptr != realpath(path.c_str(), buf)) {
            absolute = buf;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
    try {
        std::string::size_type parent_len = parent.length();
        if (0 == parent_len || "." == parent || "./" == parent) {
            combined = child;
            return true;
        }
        char last_char = parent[parent_len - 1];
        if (last_char == DIRECTORY_SYMBOL) {
            parent_len--;
        }
        combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
    try {
        std::string::size_type start = 0;
        std::string::size_type location = path_list.find(PATH_SEPARATOR);
        while (location != std::string::npos) {
            paths.push_back(path_list.substr(start, location));
            start = location + 1;
            location = path_list.find(PATH_SEPARATOR, start);
        }
        paths.push_back(path_list.substr(start, location));
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
    try {
        DIR* dir;
        struct dirent* entry;
        dir = opendir(path.c_str());
        while (dir && (entry = readdir(dir))) {
            files.push_back(entry->d_name);
        }
        closedir(dir);
        return true;
    } catch (...) {
    }
    return false;
}

#endif
<commit_msg>fix minor substr error<commit_after>// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Authors: Mark Young <marky@lunarg.com>
//          Nat Brown <natb@valvesoftware.com>
//

#include <cstring>
#include "xr_dependencies.h"

#if defined DISABLE_STD_FILESYSTEM
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 0

#else
// If the C++ macro is set to the version containing C++17, it must support
// the final C++17 package
#if __cplusplus >= 201703L
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1

#elif defined(_MSC_VER) && _MSC_VER >= 1900

#if defined(_HAS_CXX17) && _HAS_CXX17
// When MSC supports c++17 use <filesystem> package.
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#else
// MSC before c++17 need to use <experimental/filesystem> package.
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0
#endif  // !_HAS_CXX17

// Right now, GCC still only supports the experimental filesystem items starting in GCC 6
#elif (__GNUC__ >= 6)
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0

// If Clang, check for feature support
#elif defined(__clang__) && (__cpp_lib_filesystem || __cpp_lib_experimental_filesystem)
#if __cpp_lib_filesystem
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#else
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0
#endif

// If all above fails, fall back to standard C++ and OS-specific items
#else
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 0
#endif
#endif

#if USE_FINAL_FS == 1
#include <filesystem>
#define FS_PREFIX std::filesystem
#elif USE_EXPERIMENTAL_FS == 1
#if (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
#error "Windows universal application doesn't support system::experimental::filesystem"
#endif
#include <experimental/filesystem>
#define FS_PREFIX std::experimental::filesystem
#elif defined(XR_USE_PLATFORM_WIN32)
// Windows fallback includes
#include <stdint.h>
#include <direct.h>
#include <shlwapi.h>
#else
// Linux/Apple fallback includes
#include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <dirent.h>
#endif

#include "filesystem_utils.hpp"

#if defined(XR_USE_PLATFORM_WIN32)
#define PATH_SEPARATOR ';'
#define DIRECTORY_SYMBOL '\\'
#else
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
#endif

#if (USE_FINAL_FS == 1) || (USE_EXPERIMENTAL_FS == 1)
// We can use one of the C++ filesystem packages

bool FileSysUtilsIsRegularFile(const std::string& path) {
    try {
        return FS_PREFIX::is_regular_file(path);
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsDirectory(const std::string& path) {
    try {
        return FS_PREFIX::is_directory(path);
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsPathExists(const std::string& path) {
    try {
        return FS_PREFIX::exists(path);
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsAbsolutePath(const std::string& path) {
    try {
        FS_PREFIX::path file_path(path);
        return file_path.is_absolute();
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsGetCurrentPath(std::string& path) {
    try {
        FS_PREFIX::path cur_path = FS_PREFIX::current_path();
        path = cur_path.string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
    try {
        FS_PREFIX::path path_var(file_path);
        parent_path = path_var.parent_path().string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
    try {
        absolute = FS_PREFIX::absolute(path).string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
    try {
        FS_PREFIX::path parent_path(parent);
        FS_PREFIX::path child_path(child);
        FS_PREFIX::path full_path = parent_path / child_path;
        combined = full_path.string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
    try {
        std::string::size_type start = 0;
        std::string::size_type location = path_list.find(PATH_SEPARATOR);
        while (location != std::string::npos) {
            paths.push_back(path_list.substr(start, location));
            start = location + 1;
            location = path_list.find(PATH_SEPARATOR, start);
        }
        paths.push_back(path_list.substr(start, location));
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
    try {
        for (auto& dir_iter : FS_PREFIX::directory_iterator(path)) {
            files.push_back(dir_iter.path().filename().string());
        }
        return true;
    } catch (...) {
    }
    return false;
}

#elif defined(XR_OS_WINDOWS)

// Workaround for MS VS 2010/2013 don't support the experimental filesystem

bool FileSysUtilsIsRegularFile(const std::string& path) {
    try {
        return (1 != PathIsDirectoryA(path.c_str()));
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsDirectory(const std::string& path) {
    try {
        return (1 == PathIsDirectoryA(path.c_str()));
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsPathExists(const std::string& path) {
    try {
        return (1 == PathFileExistsA(path.c_str()));
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsAbsolutePath(const std::string& path) {
    try {
        if ((path[0] == '\\') || (path[1] == ':' && (path[2] == '\\' || path[2] == '/'))) {
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetCurrentPath(std::string& path) {
    try {
        char tmp_path[MAX_PATH];
        if (nullptr != _getcwd(tmp_path, MAX_PATH - 1)) {
            path = tmp_path;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
    try {
        std::string full_path;
        if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
            std::string::size_type lastSeperator = full_path.find_last_of(DIRECTORY_SYMBOL);
            parent_path = (lastSeperator == 0) ? full_path : full_path.substr(0, lastSeperator);
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
    try {
        char tmp_path[MAX_PATH];
        if (0 != GetFullPathNameA(path.c_str(), MAX_PATH, tmp_path, NULL)) {
            absolute = tmp_path;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
    try {
        std::string::size_type parent_len = parent.length();
        if (0 == parent_len || "." == parent || ".\\" == parent || "./" == parent) {
            combined = child;
            return true;
        }
        char last_char = parent[parent_len - 1];
        if (last_char == DIRECTORY_SYMBOL) {
            parent_len--;
        }
        combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
    try {
        std::string::size_type start = 0;
        std::string::size_type location = path_list.find(PATH_SEPARATOR);
        while (location != std::string::npos) {
            paths.push_back(path_list.substr(start, location));
            start = location + 1;
            location = path_list.find(PATH_SEPARATOR, start);
        }
        paths.push_back(path_list.substr(start, location));
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
    try {
        WIN32_FIND_DATAA file_data;
        HANDLE file_handle = FindFirstFileA(path.c_str(), &file_data);
        if (file_handle != INVALID_HANDLE_VALUE) {
            do {
                if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
                    files.push_back(file_data.cFileName);
                }
            } while (FindNextFileA(file_handle, &file_data));
            return true;
        }
    } catch (...) {
    }
    return false;
}

#else  // XR_OS_LINUX/XR_OS_APPLE fallback

#include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>

// simple POSIX-compatible implementation of the <filesystem> pieces used by OpenXR

bool FileSysUtilsIsRegularFile(const std::string& path) {
    try {
        struct stat path_stat;
        stat(path.c_str(), &path_stat);
        return S_ISREG(path_stat.st_mode);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsIsDirectory(const std::string& path) {
    try {
        struct stat path_stat;
        stat(path.c_str(), &path_stat);
        return S_ISDIR(path_stat.st_mode);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsPathExists(const std::string& path) {
    try {
        return (access(path.c_str(), F_OK) != -1);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsIsAbsolutePath(const std::string& path) {
    try {
        return (path[0] == DIRECTORY_SYMBOL);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetCurrentPath(std::string& path) {
    try {
        char tmp_path[PATH_MAX];
        if (nullptr != getcwd(tmp_path, PATH_MAX - 1)) {
            path = tmp_path;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
    try {
        std::string full_path;
        if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
            std::string::size_type lastSeperator = full_path.find_last_of(DIRECTORY_SYMBOL);
            parent_path = (lastSeperator == 0) ? full_path : full_path.substr(0, lastSeperator - 1);
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
    try {
        char buf[PATH_MAX];
        if (nullptr != realpath(path.c_str(), buf)) {
            absolute = buf;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
    try {
        std::string::size_type parent_len = parent.length();
        if (0 == parent_len || "." == parent || "./" == parent) {
            combined = child;
            return true;
        }
        char last_char = parent[parent_len - 1];
        if (last_char == DIRECTORY_SYMBOL) {
            parent_len--;
        }
        combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
    try {
        std::string::size_type start = 0;
        std::string::size_type location = path_list.find(PATH_SEPARATOR);
        while (location != std::string::npos) {
            paths.push_back(path_list.substr(start, location));
            start = location + 1;
            location = path_list.find(PATH_SEPARATOR, start);
        }
        paths.push_back(path_list.substr(start, location));
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
    try {
        DIR* dir;
        struct dirent* entry;
        dir = opendir(path.c_str());
        while (dir && (entry = readdir(dir))) {
            files.push_back(entry->d_name);
        }
        closedir(dir);
        return true;
    } catch (...) {
    }
    return false;
}

#endif
<|endoftext|>


<commit_before>//===-- gccas.cpp - The "optimizing assembler" used by the GCC frontend ---===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This utility is designed to be used by the GCC frontend for creating bytecode
// files from its intermediate LLVM assembly.  The requirements for this utility
// are thus slightly different than that of the standard `as' util.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Analysis/LoadValueNumbering.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar.h"
#include "Support/CommandLine.h"
#include "Support/Signals.h"
#include <memory>
#include <fstream>

using namespace llvm;

namespace {
  cl::opt<std::string>
  InputFilename(cl::Positional,cl::desc("<input llvm assembly>"),cl::init("-"));

  cl::opt<std::string>
  OutputFilename("o", cl::desc("Override output filename"),
                 cl::value_desc("filename"));

  cl::opt<bool>
  Verify("verify", cl::desc("Verify each pass result"));

  cl::opt<bool>
  DisableInline("disable-inlining", cl::desc("Do not run the inliner pass"));
}

static inline void addPass(PassManager &PM, Pass *P) {
  // Add the pass to the pass manager...
  PM.add(P);

  // If we are verifying all of the intermediate steps, add the verifier...
  if (Verify) PM.add(createVerifierPass());
}

void AddConfiguredTransformationPasses(PassManager &PM) {
  PM.add(createVerifierPass());                  // Verify that input is correct
  addPass(PM, createLowerSetJmpPass());          // Lower llvm.setjmp/.longjmp
  addPass(PM, createFunctionResolvingPass());    // Resolve (...) functions
  addPass(PM, createCFGSimplificationPass());    // Clean up disgusting code
  addPass(PM, createRaiseAllocationsPass());     // call %malloc -> malloc inst
  addPass(PM, createGlobalDCEPass());            // Remove unused globals
  addPass(PM, createIPConstantPropagationPass());// IP Constant Propagation
  addPass(PM, createDeadArgEliminationPass());   // Dead argument elimination

  addPass(PM, createPruneEHPass());              // Remove dead EH info

  if (!DisableInline)
    addPass(PM, createFunctionInliningPass());   // Inline small functions

  addPass(PM, createInstructionCombiningPass()); // Cleanup code for raise

  // HACK HACK HACK.  This pass should be extended to support calls like 'call
  // (const expr cast (free))(Ty *).  Until it does so, we have to run it after
  // instruction combining.  This should be removed after PLDI!
  addPass(PM, createRaiseAllocationsPass());     // call %malloc -> malloc inst

  addPass(PM, createRaisePointerReferencesPass());// Recover type information
  addPass(PM, createTailDuplicationPass());      // Simplify cfg by copying code
  addPass(PM, createCFGSimplificationPass());    // Merge & remove BBs
  addPass(PM, createScalarReplAggregatesPass()); // Break up aggregate allocas
  addPass(PM, createTailCallEliminationPass());  // Eliminate tail calls
  addPass(PM, createInstructionCombiningPass()); // Combine silly seq's

  addPass(PM, createReassociatePass());          // Reassociate expressions
  addPass(PM, createInstructionCombiningPass()); // Combine silly seq's
  addPass(PM, createCFGSimplificationPass());    // Merge & remove BBs
  addPass(PM, createLICMPass());                 // Hoist loop invariants
  addPass(PM, createLoadValueNumberingPass());   // GVN for load instructions
  addPass(PM, createGCSEPass());                 // Remove common subexprs
  addPass(PM, createSCCPPass());                 // Constant prop with SCCP

  // Run instcombine after redundancy elimination to exploit opportunities
  // opened up by them.
  addPass(PM, createInstructionCombiningPass());
  addPass(PM, createIndVarSimplifyPass());       // Canonicalize indvars
  addPass(PM, createAggressiveDCEPass());        // SSA based 'Aggressive DCE'
  addPass(PM, createCFGSimplificationPass());    // Merge & remove BBs
  addPass(PM, createDeadTypeEliminationPass());  // Eliminate dead types
  addPass(PM, createConstantMergePass());        // Merge dup global constants
}

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv, " llvm .s -> .o assembler for GCC\n");

  std::auto_ptr<Module> M;
  try {
    // Parse the file now...
    M.reset(ParseAssemblyFile(InputFilename));
  } catch (const ParseException &E) {
    std::cerr << argv[0] << ": " << E.getMessage() << "\n";
    return 1;
  }

  if (M.get() == 0) {
    std::cerr << argv[0] << ": assembly didn't read correctly.\n";
    return 1;
  }

  std::ostream *Out = 0;
  if (OutputFilename == "") {   // Didn't specify an output filename?
    if (InputFilename == "-") {
      OutputFilename = "-";
    } else {
      std::string IFN = InputFilename;
      int Len = IFN.length();
      if (IFN[Len-2] == '.' && IFN[Len-1] == 's') {   // Source ends in .s?
        OutputFilename = std::string(IFN.begin(), IFN.end()-2);
      } else {
        OutputFilename = IFN;   // Append a .o to it
      }
      OutputFilename += ".o";
    }
  }

  if (OutputFilename == "-")
    Out = &std::cout;
  else {
    Out = new std::ofstream(OutputFilename.c_str(), std::ios::out);

    // Make sure that the Out file gets unlinked from the disk if we get a
    // signal
    RemoveFileOnSignal(OutputFilename);
  }

  if (!Out->good()) {
    std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
    return 1;
  }

  // In addition to just parsing the input from GCC, we also want to spiff it up
  // a little bit.  Do this now.
  //
  PassManager Passes;

  // Add an appropriate TargetData instance for this module...
  Passes.add(new TargetData("gccas", M.get()));

  // Add all of the transformation passes to the pass manager to do the cleanup
  // and optimization of the GCC output.
  //
  AddConfiguredTransformationPasses(Passes);

  // Write bytecode to file...
  Passes.add(new WriteBytecodePass(Out));

  // Run our queue of passes all at once now, efficiently.
  Passes.run(*M.get());

  if (Out != &std::cout) delete Out;
  return 0;
}
<commit_msg>It is now after pldi.  This issue has been fixed, so remove the hack<commit_after>//===-- gccas.cpp - The "optimizing assembler" used by the GCC frontend ---===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This utility is designed to be used by the GCC frontend for creating bytecode
// files from its intermediate LLVM assembly.  The requirements for this utility
// are thus slightly different than that of the standard `as' util.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Analysis/LoadValueNumbering.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar.h"
#include "Support/CommandLine.h"
#include "Support/Signals.h"
#include <memory>
#include <fstream>

using namespace llvm;

namespace {
  cl::opt<std::string>
  InputFilename(cl::Positional,cl::desc("<input llvm assembly>"),cl::init("-"));

  cl::opt<std::string>
  OutputFilename("o", cl::desc("Override output filename"),
                 cl::value_desc("filename"));

  cl::opt<bool>
  Verify("verify", cl::desc("Verify each pass result"));

  cl::opt<bool>
  DisableInline("disable-inlining", cl::desc("Do not run the inliner pass"));
}

static inline void addPass(PassManager &PM, Pass *P) {
  // Add the pass to the pass manager...
  PM.add(P);

  // If we are verifying all of the intermediate steps, add the verifier...
  if (Verify) PM.add(createVerifierPass());
}

void AddConfiguredTransformationPasses(PassManager &PM) {
  PM.add(createVerifierPass());                  // Verify that input is correct
  addPass(PM, createLowerSetJmpPass());          // Lower llvm.setjmp/.longjmp
  addPass(PM, createFunctionResolvingPass());    // Resolve (...) functions
  addPass(PM, createCFGSimplificationPass());    // Clean up disgusting code
  addPass(PM, createRaiseAllocationsPass());     // call %malloc -> malloc inst
  addPass(PM, createGlobalDCEPass());            // Remove unused globals
  addPass(PM, createIPConstantPropagationPass());// IP Constant Propagation
  addPass(PM, createDeadArgEliminationPass());   // Dead argument elimination

  addPass(PM, createPruneEHPass());              // Remove dead EH info

  if (!DisableInline)
    addPass(PM, createFunctionInliningPass());   // Inline small functions

  addPass(PM, createInstructionCombiningPass()); // Cleanup code for raise
  addPass(PM, createRaisePointerReferencesPass());// Recover type information
  addPass(PM, createTailDuplicationPass());      // Simplify cfg by copying code
  addPass(PM, createCFGSimplificationPass());    // Merge & remove BBs
  addPass(PM, createScalarReplAggregatesPass()); // Break up aggregate allocas
  addPass(PM, createTailCallEliminationPass());  // Eliminate tail calls
  addPass(PM, createInstructionCombiningPass()); // Combine silly seq's

  addPass(PM, createReassociatePass());          // Reassociate expressions
  addPass(PM, createInstructionCombiningPass()); // Combine silly seq's
  addPass(PM, createCFGSimplificationPass());    // Merge & remove BBs
  addPass(PM, createLICMPass());                 // Hoist loop invariants
  addPass(PM, createLoadValueNumberingPass());   // GVN for load instructions
  addPass(PM, createGCSEPass());                 // Remove common subexprs
  addPass(PM, createSCCPPass());                 // Constant prop with SCCP

  // Run instcombine after redundancy elimination to exploit opportunities
  // opened up by them.
  addPass(PM, createInstructionCombiningPass());
  addPass(PM, createIndVarSimplifyPass());       // Canonicalize indvars
  addPass(PM, createAggressiveDCEPass());        // SSA based 'Aggressive DCE'
  addPass(PM, createCFGSimplificationPass());    // Merge & remove BBs
  addPass(PM, createDeadTypeEliminationPass());  // Eliminate dead types
  addPass(PM, createConstantMergePass());        // Merge dup global constants
}

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv, " llvm .s -> .o assembler for GCC\n");

  std::auto_ptr<Module> M;
  try {
    // Parse the file now...
    M.reset(ParseAssemblyFile(InputFilename));
  } catch (const ParseException &E) {
    std::cerr << argv[0] << ": " << E.getMessage() << "\n";
    return 1;
  }

  if (M.get() == 0) {
    std::cerr << argv[0] << ": assembly didn't read correctly.\n";
    return 1;
  }

  std::ostream *Out = 0;
  if (OutputFilename == "") {   // Didn't specify an output filename?
    if (InputFilename == "-") {
      OutputFilename = "-";
    } else {
      std::string IFN = InputFilename;
      int Len = IFN.length();
      if (IFN[Len-2] == '.' && IFN[Len-1] == 's') {   // Source ends in .s?
        OutputFilename = std::string(IFN.begin(), IFN.end()-2);
      } else {
        OutputFilename = IFN;   // Append a .o to it
      }
      OutputFilename += ".o";
    }
  }

  if (OutputFilename == "-")
    Out = &std::cout;
  else {
    Out = new std::ofstream(OutputFilename.c_str(), std::ios::out);

    // Make sure that the Out file gets unlinked from the disk if we get a
    // signal
    RemoveFileOnSignal(OutputFilename);
  }

  if (!Out->good()) {
    std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
    return 1;
  }

  // In addition to just parsing the input from GCC, we also want to spiff it up
  // a little bit.  Do this now.
  //
  PassManager Passes;

  // Add an appropriate TargetData instance for this module...
  Passes.add(new TargetData("gccas", M.get()));

  // Add all of the transformation passes to the pass manager to do the cleanup
  // and optimization of the GCC output.
  //
  AddConfiguredTransformationPasses(Passes);

  // Write bytecode to file...
  Passes.add(new WriteBytecodePass(Out));

  // Run our queue of passes all at once now, efficiently.
  Passes.run(*M.get());

  if (Out != &std::cout) delete Out;
  return 0;
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
// LLVM 'GCCAS' UTILITY
//
//  This utility is designed to be used by the GCC frontend for creating
// bytecode files from it's intermediate llvm assembly.  The requirements for
// this utility are thus slightly different than that of the standard as util.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/Transforms/RaisePointerReferences.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Analysis/LoadValueNumbering.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Target/TargetData.h"
#include "Support/CommandLine.h"
#include "Support/Signals.h"
#include <memory>
#include <fstream>
using std::cerr;

// FIXME: This should eventually be parameterized...
static TargetData TD("opt target");

static cl::opt<std::string>
InputFilename(cl::Positional, cl::desc("<input llvm assembly>"), cl::Required);

static cl::opt<std::string>
OutputFilename("o", cl::desc("Override output filename"),
               cl::value_desc("filename"));

static cl::opt<int>
RunNPasses("stopAfterNPasses",
           cl::desc("Only run the first N passes of gccas"), cl::Hidden,
           cl::value_desc("# passes"));

static cl::opt<bool>
Verify("verify", cl::desc("Verify each pass result"));

static inline void addPass(PassManager &PM, Pass *P) {
  static int NumPassesCreated = 0;

  // If we haven't already created the number of passes that was requested...
  if (RunNPasses == 0 || RunNPasses > NumPassesCreated) {
    // Add the pass to the pass manager...
    PM.add(P);

    // If we are verifying all of the intermediate steps, add the verifier...
    if (Verify) PM.add(createVerifierPass());

    // Keep track of how many passes we made for -stopAfterNPasses
    ++NumPassesCreated;
  } else {
    delete P;             // We don't want this pass to run, just delete it now
  }
}

void AddConfiguredTransformationPasses(PassManager &PM) {
  if (Verify) PM.add(createVerifierPass());

  addPass(PM, createFunctionResolvingPass());    // Resolve (...) functions
  addPass(PM, createGlobalDCEPass());            // Kill unused uinit g-vars
  addPass(PM, createDeadTypeEliminationPass());  // Eliminate dead types
  addPass(PM, createConstantMergePass());        // Merge dup global constants
  addPass(PM, createVerifierPass());             // Verify that input is correct
  addPass(PM, createDeadInstEliminationPass());  // Remove Dead code/vars
  addPass(PM, createRaiseAllocationsPass());     // call %malloc -> malloc inst
  addPass(PM, createIndVarSimplifyPass());       // Simplify indvars
  addPass(PM, createRaisePointerReferencesPass(TD));// Recover type information
  addPass(PM, createInstructionCombiningPass()); // Combine silly seq's
  addPass(PM, createPromoteMemoryToRegister());  // Promote alloca's to regs
  addPass(PM, createReassociatePass());          // Reassociate expressions
  //addPass(PM, createCorrelatedExpressionEliminationPass());// Kill corr branches
  addPass(PM, createInstructionCombiningPass()); // Combine silly seq's
  addPass(PM, createCFGSimplificationPass());    // Merge & remove BBs
  addPass(PM, createLICMPass());                 // Hoist loop invariants
  addPass(PM, createLoadValueNumberingPass());   // GVN for load instructions
  addPass(PM, createGCSEPass());                 // Remove common subexprs
  addPass(PM, createSCCPPass());                 // Constant prop with SCCP

  // Run instcombine after redundancy elimination to exploit opportunities
  // opened up by them.
  addPass(PM, createInstructionCombiningPass());
  addPass(PM, createAggressiveDCEPass());        // SSA based 'Agressive DCE'
  addPass(PM, createCFGSimplificationPass());    // Merge & remove BBs
}

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv, " llvm .s -> .o assembler for GCC\n");

  std::auto_ptr<Module> M;
  try {
    // Parse the file now...
    M.reset(ParseAssemblyFile(InputFilename));
  } catch (const ParseException &E) {
    cerr << argv[0] << ": " << E.getMessage() << "\n";
    return 1;
  }

  if (M.get() == 0) {
    cerr << argv[0] << ": assembly didn't read correctly.\n";
    return 1;
  }

  if (OutputFilename == "") {   // Didn't specify an output filename?
    std::string IFN = InputFilename;
    int Len = IFN.length();
    if (IFN[Len-2] == '.' && IFN[Len-1] == 's') {   // Source ends in .s?
      OutputFilename = std::string(IFN.begin(), IFN.end()-2);
    } else {
      OutputFilename = IFN;   // Append a .o to it
    }
    OutputFilename += ".o";
  }

  std::ofstream Out(OutputFilename.c_str(), std::ios::out);
  if (!Out.good()) {
    cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
    return 1;
  }

  // Make sure that the Out file gets unlink'd from the disk if we get a SIGINT
  RemoveFileOnSignal(OutputFilename);

  // In addition to just parsing the input from GCC, we also want to spiff it up
  // a little bit.  Do this now.
  //
  PassManager Passes;

  // Add all of the transformation passes to the pass manager to do the cleanup
  // and optimization of the GCC output.
  //
  AddConfiguredTransformationPasses(Passes);

  // Write bytecode to file...
  Passes.add(new WriteBytecodePass(&Out));

  // Run our queue of passes all at once now, efficiently.
  Passes.run(*M.get());
  return 0;
}
<commit_msg>Namespacify command line options<commit_after>//===----------------------------------------------------------------------===//
// LLVM 'GCCAS' UTILITY
//
//  This utility is designed to be used by the GCC frontend for creating
// bytecode files from it's intermediate llvm assembly.  The requirements for
// this utility are thus slightly different than that of the standard as util.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/Transforms/RaisePointerReferences.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Analysis/LoadValueNumbering.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Target/TargetData.h"
#include "Support/CommandLine.h"
#include "Support/Signals.h"
#include <memory>
#include <fstream>
using std::cerr;

namespace {
  // FIXME: This should eventually be parameterized...
  TargetData TD("gccas target");

  cl::opt<std::string>
  InputFilename(cl::Positional, cl::desc("<input llvm assembly>"),cl::Required);

  cl::opt<std::string>
  OutputFilename("o", cl::desc("Override output filename"),
                 cl::value_desc("filename"));

  cl::opt<int>
  RunNPasses("stopAfterNPasses",
             cl::desc("Only run the first N passes of gccas"), cl::Hidden,
             cl::value_desc("# passes"));

  cl::opt<bool>
  Verify("verify", cl::desc("Verify each pass result"));

}

static inline void addPass(PassManager &PM, Pass *P) {
  static int NumPassesCreated = 0;

  // If we haven't already created the number of passes that was requested...
  if (RunNPasses == 0 || RunNPasses > NumPassesCreated) {
    // Add the pass to the pass manager...
    PM.add(P);

    // If we are verifying all of the intermediate steps, add the verifier...
    if (Verify) PM.add(createVerifierPass());

    // Keep track of how many passes we made for -stopAfterNPasses
    ++NumPassesCreated;
  } else {
    delete P;             // We don't want this pass to run, just delete it now
  }
}

void AddConfiguredTransformationPasses(PassManager &PM) {
  if (Verify) PM.add(createVerifierPass());

  addPass(PM, createFunctionResolvingPass());    // Resolve (...) functions
  addPass(PM, createGlobalDCEPass());            // Kill unused uinit g-vars
  addPass(PM, createDeadTypeEliminationPass());  // Eliminate dead types
  addPass(PM, createConstantMergePass());        // Merge dup global constants
  addPass(PM, createVerifierPass());             // Verify that input is correct
  addPass(PM, createDeadInstEliminationPass());  // Remove Dead code/vars
  addPass(PM, createRaiseAllocationsPass());     // call %malloc -> malloc inst
  addPass(PM, createIndVarSimplifyPass());       // Simplify indvars
  addPass(PM, createRaisePointerReferencesPass(TD));// Recover type information
  addPass(PM, createInstructionCombiningPass()); // Combine silly seq's
  addPass(PM, createPromoteMemoryToRegister());  // Promote alloca's to regs
  addPass(PM, createReassociatePass());          // Reassociate expressions
  //addPass(PM, createCorrelatedExpressionEliminationPass());// Kill corr branches
  addPass(PM, createInstructionCombiningPass()); // Combine silly seq's
  addPass(PM, createCFGSimplificationPass());    // Merge & remove BBs
  addPass(PM, createLICMPass());                 // Hoist loop invariants
  addPass(PM, createLoadValueNumberingPass());   // GVN for load instructions
  addPass(PM, createGCSEPass());                 // Remove common subexprs
  addPass(PM, createSCCPPass());                 // Constant prop with SCCP

  // Run instcombine after redundancy elimination to exploit opportunities
  // opened up by them.
  addPass(PM, createInstructionCombiningPass());
  addPass(PM, createAggressiveDCEPass());        // SSA based 'Agressive DCE'
  addPass(PM, createCFGSimplificationPass());    // Merge & remove BBs
}

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv, " llvm .s -> .o assembler for GCC\n");

  std::auto_ptr<Module> M;
  try {
    // Parse the file now...
    M.reset(ParseAssemblyFile(InputFilename));
  } catch (const ParseException &E) {
    cerr << argv[0] << ": " << E.getMessage() << "\n";
    return 1;
  }

  if (M.get() == 0) {
    cerr << argv[0] << ": assembly didn't read correctly.\n";
    return 1;
  }

  if (OutputFilename == "") {   // Didn't specify an output filename?
    std::string IFN = InputFilename;
    int Len = IFN.length();
    if (IFN[Len-2] == '.' && IFN[Len-1] == 's') {   // Source ends in .s?
      OutputFilename = std::string(IFN.begin(), IFN.end()-2);
    } else {
      OutputFilename = IFN;   // Append a .o to it
    }
    OutputFilename += ".o";
  }

  std::ofstream Out(OutputFilename.c_str(), std::ios::out);
  if (!Out.good()) {
    cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
    return 1;
  }

  // Make sure that the Out file gets unlink'd from the disk if we get a SIGINT
  RemoveFileOnSignal(OutputFilename);

  // In addition to just parsing the input from GCC, we also want to spiff it up
  // a little bit.  Do this now.
  //
  PassManager Passes;

  // Add all of the transformation passes to the pass manager to do the cleanup
  // and optimization of the GCC output.
  //
  AddConfiguredTransformationPasses(Passes);

  // Write bytecode to file...
  Passes.add(new WriteBytecodePass(&Out));

  // Run our queue of passes all at once now, efficiently.
  Passes.run(*M.get());
  return 0;
}
<|endoftext|>