<commit_before>// SqlPipe.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

// The following come from "SQL Server 2005 Virtual Backup Device Interface (VDI) Specification"
// http://www.microsoft.com/downloads/en/details.aspx?familyid=416f8a51-65a3-4e8e-a4c8-adfe15e850fc
#include "vdi/vdi.h"        // interface declaration
#include "vdi/vdierror.h"   // error constants
#include "vdi/vdiguid.h"    // define the interface identifiers.

// Globals
TCHAR* _serverInstanceName;
bool _optionQuiet = false;

// printf to stdout (if -q quiet option isn't specified)
void log(const TCHAR* format, ...)
{
	if (_optionQuiet)
		return;

	// Basically do a fprintf to stderr. The va_* stuff is just to handle variable args
	va_list arglist;
	va_start(arglist, format);
	vfwprintf(stderr, format, arglist);
}

// printf to stdout (regardless of -q quiet option)
void err(const TCHAR* format, ...)
{
	va_list arglist;
	va_start(arglist, format);
	vfwprintf(stderr, format, arglist);
}

// Get human-readable message given a HRESULT
_bstr_t errorMessage(DWORD messageId)
{
	LPTSTR szMessage;
	if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, messageId, 0, (LPTSTR)&szMessage, 0, NULL))
	{
		szMessage = (LPTSTR)LocalAlloc(LPTR, 50 * sizeof(TCHAR));
		_snwprintf(szMessage, 50 * sizeof(TCHAR), L"Unknown error 0x%x.\n", messageId);
	}
	_bstr_t retval = szMessage;
	LocalFree(szMessage);
	return retval;
}

// Execute the given SQL against _serverInstanceName
DWORD executeSql(TCHAR* sql)
{
	//log(L"\nexecuteSql '%s'\n", sql);
	HRESULT hr;

	// Use '_Connection_Deprecated' interface for maximum MDAC compatibility
	// BTW: Windows 7 SP1 introduced _Connection_Deprecated: See:
    //   http://social.msdn.microsoft.com/Forums/en/windowsgeneraldevelopmentissues/thread/3a4ce946-effa-4f77-98a6-34f11c6b5a13
	// and
	//   http://support.microsoft.com/kb/2517589
	_Connection_DeprecatedPtr conn;
	hr = conn.CreateInstance(__uuidof(Connection));
	if (FAILED(hr))
	{
		err(L"ADODB.Connection CreateInstance failed: %s", (TCHAR*)errorMessage(hr));
		return hr;
	}

	// "lpc:..." ensures shared memory...
	_bstr_t serverName = "lpc:.";
	if (_serverInstanceName != NULL)
		serverName += "\\" + _bstr_t(_serverInstanceName);

	try
	{
		conn->ConnectionString = "Provider=SQLOLEDB; Data Source=" + serverName + "; Initial Catalog=master; Integrated Security=SSPI;";
		//log(L"> Connect: %s\n", (TCHAR*)conn->ConnectionString);
		conn->ConnectionTimeout = 25;
		conn->Open("", "", "", adConnectUnspecified);
	}
	catch(_com_error e)
	{
		err(L"\nFailed to open connection to '" + serverName + L"': ");
		err(L"%s [%s]\n", (TCHAR*)e.Description(), (TCHAR*)e.Source());
		return e.Error();
	}

	try
	{
		//log(L"> SQL: %s\n", sql);
		variant_t recordsAffected;
		conn->CommandTimeout = 0;
		conn->Execute(sql, &recordsAffected, adExecuteNoRecords);
		conn->Close();
	}
	catch(_com_error e)
	{
		err(L"\nQuery failed: '%s'\n\n%s [%s]\n", sql, (TCHAR*)e.Description(), (TCHAR*)e.Source());
		//err(L"  Errors:\n", conn->Errors->Count);
		//for (int i = 0; i < conn->Errors->Count; i++)
		//	err(L"  - %s\n\n", (TCHAR*)conn->Errors->Item[i]->Description);

		conn->Close();
		return e.Error();
	}

	return 0;
}

// Transfer data from virtualDevice to backupfile or vice-versa
HRESULT performTransfer(IClientVirtualDevice* virtualDevice, FILE* backupfile)
{
	VDC_Command *   cmd;
	DWORD           completionCode;
	DWORD           bytesTransferred;
	HRESULT         hr;
	DWORD           totalBytes = 0;

	while (SUCCEEDED (hr = virtualDevice->GetCommand(3 * 60 * 1000, &cmd)))
	{
		//log(L">command %d, size %d\n", cmd->commandCode, cmd->size);
		bytesTransferred = 0;

		switch (cmd->commandCode)
		{
		case VDC_Read:

			while(bytesTransferred < cmd->size)
				bytesTransferred += fread(cmd->buffer + bytesTransferred, 1, cmd->size - bytesTransferred, backupfile);

			totalBytes += bytesTransferred;
			log(L"%d bytes read                               \r", totalBytes);

			cmd->size = bytesTransferred;

			completionCode = ERROR_SUCCESS;
			break;

		case VDC_Write:
			//log(L"VDC_Write - size: %d\r\n", cmd->size);

			while(bytesTransferred < cmd->size)
				bytesTransferred += fwrite(cmd->buffer + bytesTransferred, 1, cmd->size - bytesTransferred, backupfile);

			totalBytes += bytesTransferred;

			log(L"%d bytes written\r", totalBytes);
			completionCode = ERROR_SUCCESS;
			break;

		case VDC_Flush:
			//log(L"\nVDC_Flush %d\n", cmd->size);
			completionCode = ERROR_SUCCESS;
			break;

		case VDC_ClearError:
			log(L"\nVDC_ClearError\n");
			//Debug::WriteLine("VDC_ClearError");
			completionCode = ERROR_SUCCESS;
			break;

		default:
			// If command is unknown...
			completionCode = ERROR_NOT_SUPPORTED;
		}

		hr = virtualDevice->CompleteCommand(cmd, completionCode, bytesTransferred, 0);
		if (FAILED(hr))
		{
			err(L"\nvirtualDevice->CompleteCommand failed: %s\n", (TCHAR*)errorMessage(hr));
			return hr;
		}
	}

	log(L"\n");

	if (hr != VD_E_CLOSE)
	{
		err(L"virtualDevice->GetCommand failed: ");
		if (hr == VD_E_TIMEOUT)
			err(L" timeout awaiting data.\n");
		else if (hr == VD_E_ABORT)
			err(L" transfer was aborted.\n");
		else
			err(L"%s\n", (TCHAR*)errorMessage(hr));

		return hr;
	}

	return NOERROR;
}

// Entry point
int _tmain(int argc, _TCHAR* argv[])
{
	if (argc < 3)
	{
		err(L"\n\
Action and database required.\n\
\n\
Usage: sqlpipe backup|restore <database> [options]\n\
Options:\n\
  -q Quiet, don't print messages to STDERR\n\
  -i \"instancename\"\n\
  -f \"file\" Write/read file instead of STDOUT/STDIN\n");
		return 1;
	}

	TCHAR* command = _wcslwr(argv[1]);
	TCHAR* databaseName = argv[2];

	TCHAR* filePath = NULL;

	// Parse options
	for (int i = 0; i < argc; i++)
	{
		TCHAR* arg = _wcslwr(_wcsdup(argv[i]));

		if (wcscmp(arg, L"-q") == 0)
			_optionQuiet = true;

		if (wcscmp(arg, L"-i") == 0)
			_serverInstanceName = argv[i+1];

		if (wcscmp(arg, L"-f") == 0)
			filePath = argv[i+1];

		free(arg);
	}

	HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
	if (FAILED(hr))
	{
		// Switching from apartment to multi-threaded is OK
		if(hr != RPC_E_CHANGED_MODE)
		{
			err(L"CoInitializeEx failed: ", hr);
			return 1;
		}
	}

	// Create Device Set
	IClientVirtualDeviceSet2 * virtualDeviceSet;
	hr = CoCreateInstance(
		CLSID_MSSQL_ClientVirtualDeviceSet,
		NULL,
		CLSCTX_INPROC_SERVER,
		IID_IClientVirtualDeviceSet2,
		(void**)&virtualDeviceSet);

	if (FAILED(hr))
	{
		err(L"Could not create VDI component. Check registration of SQLVDI.DLL. %s\n", (TCHAR*)errorMessage(hr));
		return 2;
	}

	// Generate virtualDeviceName
	TCHAR virtualDeviceName[39];
	GUID guid; CoCreateGuid(&guid);
	StringFromGUID2(guid, virtualDeviceName, sizeof(virtualDeviceName));

	// Create Device
	VDConfig vdConfig = {0};
	vdConfig.deviceCount = 1;
	hr = virtualDeviceSet->CreateEx(_serverInstanceName, virtualDeviceName, &vdConfig);
	if (!SUCCEEDED (hr))
	{
		err(L"IClientVirtualDeviceSet2.CreateEx failed\r\n");

		switch(hr)
		{
		case VD_E_INSTANCE_NAME:
			err(L"Didn't recognize the SQL Server instance name '"+ _bstr_t(_serverInstanceName) + L"'.\r\n");
			break;
		case E_ACCESSDENIED:
			err(L"Access Denied: You must be logged in as a Windows administrator to create virtual devices.\r\n");
			break;
		default:
			err(L"%s\n", (TCHAR*)errorMessage(hr));
			break;
		}
		return 3;
	}

	TCHAR* sql;
	FILE* backupFile = NULL;
	if (wcscmp(command, L"backup") == 0)
	{
		sql = "BACKUP DATABASE [" + _bstr_t(databaseName) + "] TO VIRTUAL_DEVICE = '" + virtualDeviceName + "'";
		if (filePath == NULL)
			backupFile = stdout;
		else
		{
			backupFile = _wfopen(filePath, L"w");
			if (backupFile == NULL)
			{
				err(L"Error creating '%s': %s\n", filePath, _wcserror(errno));
				return errno;
			}
		}
	}
	else if(wcscmp(command, L"restore") == 0)
	{
		hr = executeSql("CREATE DATABASE ["+ _bstr_t(databaseName) +"]");
		if (FAILED(hr))
			return hr;

		sql = "RESTORE DATABASE [" + _bstr_t(databaseName) + "] FROM VIRTUAL_DEVICE = '" + virtualDeviceName + "' WITH REPLACE";
		if (filePath == NULL)
			backupFile = stdin;
		else
		{
			backupFile = _wfopen(filePath, L"r");
			if (backupFile == NULL)
			{
				err(L"Error opening '%s': %s\n", filePath, _wcserror(errno));
				return errno;
			}
		}
	}
	else
	{
		err(L"Unsupported command '%s': only BACKUP or RESTORE are supported.\n", command);
		return 1;
	}

	// Invoke backup on separate thread because virtualDeviceSet->GetConfiguration will block until "BACKUP DATABASE..."
	DWORD threadId;
	HANDLE executeSqlThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&executeSql, sql, 0, &threadId);

	// Ready...
	hr = virtualDeviceSet->GetConfiguration(30000, &vdConfig);
	if (FAILED(hr))
	{
		err(L"\n%s: virtualDeviceSet->GetConfiguration failed: ", command);
		if (hr == VD_E_TIMEOUT)
			err(L"Timed out waiting for backup to be initiated.\n");
		else
			err(L"%s\n", (TCHAR*)errorMessage(hr));
		return 3;
	}

	// Steady...
	IClientVirtualDevice *virtualDevice = NULL;
	hr = virtualDeviceSet->OpenDevice(virtualDeviceName, &virtualDevice);
	if (FAILED(hr))
	{
		err(L"virtualDeviceSet->OpenDevice failed: 0x%x - ");
		if (hr == VD_E_TIMEOUT)
			err(L" timeout.\n");
		else
			err(L" %s.\n", (TCHAR*)errorMessage(hr));
		return 4;
	}

	// Go
	_setmode(_fileno(backupFile), _O_BINARY); //ensure \n's in STDOUT don't get tampered with
	hr = performTransfer(virtualDevice, backupFile);

	WaitForSingleObject(executeSqlThread, 5000);

	// Tidy up
	CloseHandle(executeSqlThread);
	virtualDeviceSet->Close();
	virtualDevice->Release();
	virtualDeviceSet->Release();

	//log(L"%s: Finished.\n", command);
	return hr;
}
<commit_msg>refactor out functions `executeRecordset` and `mountAndTransferVirtualDevice`<commit_after>// SqlPipe.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

// The following come from "SQL Server 2005 Virtual Backup Device Interface (VDI) Specification"
// http://www.microsoft.com/downloads/en/details.aspx?familyid=416f8a51-65a3-4e8e-a4c8-adfe15e850fc
#include "vdi/vdi.h"        // interface declaration
#include "vdi/vdierror.h"   // error constants
#include "vdi/vdiguid.h"    // define the interface identifiers.

// Globals
TCHAR* _serverInstanceName;
bool _optionQuiet = false;

// printf to stdout (if -q quiet option isn't specified)
void log(const TCHAR* format, ...)
{
	if (_optionQuiet)
		return;

	// Basically do a fprintf to stderr. The va_* stuff is just to handle variable args
	va_list arglist;
	va_start(arglist, format);
	vfwprintf(stderr, format, arglist);
}

// printf to stdout (regardless of -q quiet option)
void err(const TCHAR* format, ...)
{
	va_list arglist;
	va_start(arglist, format);
	vfwprintf(stderr, format, arglist);
}

// Get human-readable message given a HRESULT
_bstr_t errorMessage(DWORD messageId)
{
	LPTSTR szMessage;
	if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, messageId, 0, (LPTSTR)&szMessage, 0, NULL))
	{
		szMessage = (LPTSTR)LocalAlloc(LPTR, 50 * sizeof(TCHAR));
		_snwprintf(szMessage, 50 * sizeof(TCHAR), L"Unknown error 0x%x.\n", messageId);
	}
	_bstr_t retval = szMessage;
	LocalFree(szMessage);
	return retval;
}

// Execute the given SQL against _serverInstanceName
DWORD executeSql(TCHAR* sql)
{
	//log(L"\nexecuteSql '%s'\n", sql);
	HRESULT hr;

	// Use '_Connection_Deprecated' interface for maximum MDAC compatibility
	// BTW: Windows 7 SP1 introduced _Connection_Deprecated: See:
    //   http://social.msdn.microsoft.com/Forums/en/windowsgeneraldevelopmentissues/thread/3a4ce946-effa-4f77-98a6-34f11c6b5a13
	// and
	//   http://support.microsoft.com/kb/2517589
	_ConnectionPtr conn;
	hr = conn.CreateInstance(__uuidof(Connection));
	if (FAILED(hr))
	{
		err(L"ADODB.Connection CreateInstance failed: %s", (TCHAR*)errorMessage(hr));
		return hr;
	}

	// "lpc:..." ensures shared memory...
	_bstr_t serverName = "lpc:.";
	if (_serverInstanceName != NULL)
		serverName += "\\" + _bstr_t(_serverInstanceName);

	try
	{
		conn->ConnectionString = "Provider=SQLOLEDB; Data Source=" + serverName + "; Initial Catalog=master; Integrated Security=SSPI;";
		//log(L"> Connect: %s\n", (TCHAR*)conn->ConnectionString);
		conn->ConnectionTimeout = 25;
		conn->Open("", "", "", adConnectUnspecified);
	}
	catch(_com_error e)
	{
		err(L"\nFailed to open connection to '" + serverName + L"': ");
		err(L"%s [%s]\n", (TCHAR*)e.Description(), (TCHAR*)e.Source());
		return e.Error();
	}

	try
	{
		//log(L"> SQL: %s\n", sql);
		variant_t recordsAffected;
		conn->CommandTimeout = 0;
		conn->Execute(sql, &recordsAffected, adExecuteNoRecords);
		conn->Close();
	}
	catch(_com_error e)
	{
		err(L"\nQuery failed: '%s'\n\n%s [%s]\n", sql, (TCHAR*)e.Description(), (TCHAR*)e.Source());
		//err(L"  Errors:\n", conn->Errors->Count);
		//for (int i = 0; i < conn->Errors->Count; i++)
		//	err(L"  - %s\n\n", (TCHAR*)conn->Errors->Item[i]->Description);

		conn->Close();
		return e.Error();
	}

	return 0;
}

_RecordsetPtr executeRecordset(TCHAR* sql)
{
	HRESULT hr;

	_ConnectionPtr conn;
	hr = conn.CreateInstance(__uuidof(Connection));
	if (FAILED(hr))
	{
		err(L"ADODB.Connection CreateInstance failed: %s", (TCHAR*)errorMessage(hr));
		return hr;
	}

	// "lpc:..." ensures shared memory...
	_bstr_t serverName = "lpc:.";
	if (_serverInstanceName != NULL)
		serverName += "\\" + _bstr_t(_serverInstanceName);

	try
	{
		conn->ConnectionString = "Provider=SQLOLEDB; Data Source=" + serverName + "; Initial Catalog=master; Integrated Security=SSPI;";
		//log(L"> Connect: %s\n", (TCHAR*)conn->ConnectionString);
		conn->ConnectionTimeout = 25;
		conn->Open("", "", "", adConnectUnspecified);
	}
	catch(_com_error e)
	{
		err(L"\nFailed to open connection to '" + serverName + L"': ");
		err(L"%s [%s]\n", (TCHAR*)e.Description(), (TCHAR*)e.Source());
		return NULL;
	}

	try
	{
		//log(L"> SQL: %s\n", sql);
		variant_t recordsAffected;
		conn->CommandTimeout = 0;
		_RecordsetPtr recordset = conn->Execute(sql, &recordsAffected, adExecuteNoRecords);
		conn->Close();
        return recordset;
	}
	catch(_com_error e)
	{
		err(L"\nQuery failed: '%s'\n\n%s [%s]\n", sql, (TCHAR*)e.Description(), (TCHAR*)e.Source());
		//err(L"  Errors:\n", conn->Errors->Count);
		//for (int i = 0; i < conn->Errors->Count; i++)
		//	err(L"  - %s\n\n", (TCHAR*)conn->Errors->Item[i]->Description);

		conn->Close();
        return NULL;
	}

	return NULL;
}

// Transfer data from virtualDevice to backupfile or vice-versa
HRESULT performTransfer(IClientVirtualDevice* virtualDevice, FILE* backupfile)
{
	VDC_Command *   cmd;
	DWORD           completionCode;
	DWORD           bytesTransferred;
	HRESULT         hr;
	DWORD           totalBytes = 0;

	while (SUCCEEDED (hr = virtualDevice->GetCommand(3 * 60 * 1000, &cmd)))
	{
		//log(L">command %d, size %d\n", cmd->commandCode, cmd->size);
		bytesTransferred = 0;

		switch (cmd->commandCode)
		{
		case VDC_Read:

			while(bytesTransferred < cmd->size)
				bytesTransferred += fread(cmd->buffer + bytesTransferred, 1, cmd->size - bytesTransferred, backupfile);

			totalBytes += bytesTransferred;
			log(L"%d bytes read                               \r", totalBytes);

			cmd->size = bytesTransferred;

			completionCode = ERROR_SUCCESS;
			break;

		case VDC_Write:
			//log(L"VDC_Write - size: %d\r\n", cmd->size);

			while(bytesTransferred < cmd->size)
				bytesTransferred += fwrite(cmd->buffer + bytesTransferred, 1, cmd->size - bytesTransferred, backupfile);

			totalBytes += bytesTransferred;

			log(L"%d bytes written\r", totalBytes);
			completionCode = ERROR_SUCCESS;
			break;

		case VDC_Flush:
			//log(L"\nVDC_Flush %d\n", cmd->size);
			completionCode = ERROR_SUCCESS;
			break;

		case VDC_ClearError:
			log(L"\nVDC_ClearError\n");
			//Debug::WriteLine("VDC_ClearError");
			completionCode = ERROR_SUCCESS;
			break;

		default:
			// If command is unknown...
			completionCode = ERROR_NOT_SUPPORTED;
		}

		hr = virtualDevice->CompleteCommand(cmd, completionCode, bytesTransferred, 0);
		if (FAILED(hr))
		{
			err(L"\nvirtualDevice->CompleteCommand failed: %s\n", (TCHAR*)errorMessage(hr));
			return hr;
		}
	}

	log(L"\n");

	if (hr != VD_E_CLOSE)
	{
		err(L"virtualDevice->GetCommand failed: ");
		if (hr == VD_E_TIMEOUT)
			err(L" timeout awaiting data.\n");
		else if (hr == VD_E_ABORT)
			err(L" transfer was aborted.\n");
		else
			err(L"%s\n", (TCHAR*)errorMessage(hr));

		return hr;
	}

	return NOERROR;
}

int mountAndTransferVirtualDevice(TCHAR *command, HRESULT &hr, TCHAR virtualDeviceName[39], TCHAR *sql, FILE *backupFile)
{
    // Create Device Set
    IClientVirtualDeviceSet2 * virtualDeviceSet;
    hr = CoCreateInstance(
        CLSID_MSSQL_ClientVirtualDeviceSet,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IClientVirtualDeviceSet2,
        (void**)&virtualDeviceSet);

    if (FAILED(hr))
    {
        err(L"Could not create VDI component. Check registration of SQLVDI.DLL. %s\n", (TCHAR*)errorMessage(hr));
        return 2;
    }

    // Create Device
    VDConfig vdConfig = {0};
    vdConfig.deviceCount = 1;
    hr = virtualDeviceSet->CreateEx(_serverInstanceName, virtualDeviceName, &vdConfig);
    if (!SUCCEEDED (hr))
    {
        err(L"IClientVirtualDeviceSet2.CreateEx failed\r\n");

        switch(hr)
        {
        case VD_E_INSTANCE_NAME:
            err(L"Didn't recognize the SQL Server instance name '"+ _bstr_t(_serverInstanceName) + L"'.\r\n");
            break;
        case E_ACCESSDENIED:
            err(L"Access Denied: You must be logged in as a Windows administrator to create virtual devices.\r\n");
            break;
        default:
            err(L"%s\n", (TCHAR*)errorMessage(hr));
            break;
        }
        return 3;
    }

    // Invoke backup on separate thread because virtualDeviceSet->GetConfiguration will block until "BACKUP DATABASE..."
    DWORD threadId;
    HANDLE executeSqlThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&executeSql, sql, 0, &threadId);

    // Ready...
    hr = virtualDeviceSet->GetConfiguration(30000, &vdConfig);
    if (FAILED(hr))
    {
        err(L"\n%s: virtualDeviceSet->GetConfiguration failed: ", command);
        if (hr == VD_E_TIMEOUT)
            err(L"Timed out waiting for backup to be initiated.\n");
        else
            err(L"%s\n", (TCHAR*)errorMessage(hr));
        return 3;
    }

    // Steady...
    IClientVirtualDevice *virtualDevice = NULL;
    hr = virtualDeviceSet->OpenDevice(virtualDeviceName, &virtualDevice);
    if (FAILED(hr))
    {
        err(L"virtualDeviceSet->OpenDevice failed: 0x%x - ");
        if (hr == VD_E_TIMEOUT)
            err(L" timeout.\n");
        else
            err(L" %s.\n", (TCHAR*)errorMessage(hr));
        return 4;
    }

    // Go
    _setmode(_fileno(backupFile), _O_BINARY); //ensure \n's in STDOUT don't get tampered with
    hr = performTransfer(virtualDevice, backupFile);

    WaitForSingleObject(executeSqlThread, 5000);

    // Tidy up
    CloseHandle(executeSqlThread);
    virtualDeviceSet->Close();
    virtualDevice->Release();
    virtualDeviceSet->Release();
    return 0;
}

// Entry point
int _tmain(int argc, _TCHAR* argv[])
{
	if (argc < 3)
	{
		err(L"\n\
Action and database required.\n\
\n\
Usage: sqlpipe backup|restore <database> [options]\n\
Options:\n\
  -q Quiet, don't print messages to STDERR\n\
  -i \"instancename\"\n\
  -f \"file\" Write/read file instead of STDOUT/STDIN\n");
		return 1;
	}

	TCHAR* command = _wcslwr(argv[1]);
	TCHAR* databaseName = argv[2];

	TCHAR* filePath = NULL;

	// Parse options
	for (int i = 0; i < argc; i++)
	{
		TCHAR* arg = _wcslwr(_wcsdup(argv[i]));

		if (wcscmp(arg, L"-q") == 0)
			_optionQuiet = true;

		if (wcscmp(arg, L"-i") == 0)
			_serverInstanceName = argv[i+1];

		if (wcscmp(arg, L"-f") == 0)
			filePath = argv[i+1];

		free(arg);
	}

	HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
	if (FAILED(hr))
	{
		// Switching from apartment to multi-threaded is OK
		if(hr != RPC_E_CHANGED_MODE)
		{
			err(L"CoInitializeEx failed: ", hr);
			return 1;
		}
	}

    // Generate virtualDeviceName
	TCHAR virtualDeviceName[39];
	GUID guid; CoCreateGuid(&guid);
	StringFromGUID2(guid, virtualDeviceName, sizeof(virtualDeviceName));

	TCHAR* sql;
	FILE* backupFile = NULL;
	if (wcscmp(command, L"backup") == 0)
	{
		sql = "BACKUP DATABASE [" + _bstr_t(databaseName) + "] TO VIRTUAL_DEVICE = '" + virtualDeviceName + "'";
		if (filePath == NULL)
			backupFile = stdout;
		else
		{
			backupFile = _wfopen(filePath, L"w");
			if (backupFile == NULL)
			{
				err(L"Error creating '%s': %s\n", filePath, _wcserror(errno));
				return errno;
			}
		}
	}
	else if(wcscmp(command, L"restore") == 0)
	{
		hr = executeSql("CREATE DATABASE ["+ _bstr_t(databaseName) +"]");
		if (FAILED(hr))
			return hr;

        _RecordsetPtr fileList = executeRecordset("RESTORE FILELISTONLY FROM VIRTUAL_DEVICE = '" + _bstr_t(virtualDeviceName) + "'");
        _bstr_t restoreSql("RESTORE DATABASE [" + _bstr_t(databaseName) + "] FROM VIRTUAL_DEVICE = '" + virtualDeviceName + "' WITH");
        while(!fileList->EndOfFile)
        {
            _bstr_t fileType(fileList->Fields->GetItem("Type")->Value);
            _bstr_t logicalName = fileList->Fields->GetItem("LogicalName")->Value;
            restoreSql += " MOVE '" + logicalName + "' TO 'C:\\temp\\foo\\" +  logicalName + ".xdf'";
            fileList->MoveNext();
        }
        err(restoreSql);

        hr = mountAndTransferVirtualDevice(command, hr, virtualDeviceName, sql, backupFile);

		sql = "RESTORE DATABASE [" + _bstr_t(databaseName) + "] FROM VIRTUAL_DEVICE = '" + virtualDeviceName + "' WITH REPLACE";
		if (filePath == NULL)
			backupFile = stdin;
		else
		{
			backupFile = _wfopen(filePath, L"r");
			if (backupFile == NULL)
			{
				err(L"Error opening '%s': %s\n", filePath, _wcserror(errno));
				return errno;
			}
		}
	}
	else
	{
		err(L"Unsupported command '%s': only BACKUP or RESTORE are supported.\n", command);
		return 1;
	}

    hr = mountAndTransferVirtualDevice(command, hr, virtualDeviceName, sql, backupFile);

	//log(L"%s: Finished.\n", command);
	return hr;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 Patrizio Bekerle -- http://www.bekerle.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 * for more details.
 *
 */

#include "qtexteditsearchwidget.h"
#include "ui_qtexteditsearchwidget.h"
#include <QEvent>
#include <QKeyEvent>
#include <QDebug>

QTextEditSearchWidget::QTextEditSearchWidget(QTextEdit *parent) :
    QWidget(parent),
    ui(new Ui::QTextEditSearchWidget)
{
    ui->setupUi(this);
    _textEdit = parent;
    hide();

    QObject::connect(ui->closeButton, SIGNAL(clicked()),
                     this, SLOT(deactivate()));
    QObject::connect(ui->searchLineEdit, SIGNAL(textChanged(const QString &)),
                     this, SLOT(searchLineEditTextChanged(const QString &)));
    QObject::connect(ui->searchDownButton, SIGNAL(clicked()),
                     this, SLOT(doSearchDown()));
    QObject::connect(ui->searchUpButton, SIGNAL(clicked()),
                     this, SLOT(doSearchUp()));
    QObject::connect(ui->replaceToggleButton, SIGNAL(toggled(bool)),
                     this, SLOT(setReplaceMode(bool)));
    QObject::connect(ui->replaceButton, SIGNAL(clicked()),
                     this, SLOT(doReplace()));
    QObject::connect(ui->replaceAllButton, SIGNAL(clicked()),
                     this, SLOT(doReplaceAll()));

    installEventFilter(this);
    ui->searchLineEdit->installEventFilter(this);
    ui->replaceLineEdit->installEventFilter(this);

#ifdef Q_OS_MAC
    // set the spacing to 8 for OS X
    layout()->setSpacing(8);
    ui->buttonFrame->layout()->setSpacing(9);

    // set the margin to 0 for the top buttons for OS X
    QString buttonStyle = "QPushButton {margin: 0}";
    ui->closeButton->setStyleSheet(buttonStyle);
    ui->searchDownButton->setStyleSheet(buttonStyle);
    ui->searchUpButton->setStyleSheet(buttonStyle);
    ui->replaceToggleButton->setStyleSheet(buttonStyle);
    ui->matchCaseSensitiveButton->setStyleSheet(buttonStyle);
#endif
}

QTextEditSearchWidget::~QTextEditSearchWidget() {
    delete ui;
}

void QTextEditSearchWidget::activate() {
    setReplaceMode(false);
    show();
    ui->searchLineEdit->setFocus();
    ui->searchLineEdit->selectAll();
    doSearchDown();
}

void QTextEditSearchWidget::activateReplace() {
    ui->searchLineEdit->setText(_textEdit->textCursor().selectedText());
    ui->searchLineEdit->selectAll();
    activate();
    setReplaceMode(true);
}

void QTextEditSearchWidget::deactivate() {
    hide();
    _textEdit->setFocus();
}

void QTextEditSearchWidget::setReplaceMode(bool enabled) {
    ui->replaceToggleButton->setChecked(enabled);
    ui->replaceLabel->setVisible(enabled);
    ui->replaceLineEdit->setVisible(enabled);
    ui->modeLabel->setVisible(enabled);
    ui->buttonFrame->setVisible(enabled);
    ui->matchCaseSensitiveButton->setVisible(enabled);
}

bool QTextEditSearchWidget::eventFilter(QObject *obj, QEvent *event) {
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);

        if (keyEvent->key() == Qt::Key_Escape) {
            deactivate();
            return true;
        } else if ((keyEvent->modifiers().testFlag(Qt::ShiftModifier) &&
                  (keyEvent->key() == Qt::Key_Return)) ||
                 (keyEvent->key() == Qt::Key_Up)) {
            doSearchUp();
            return true;
        } else if ((keyEvent->key() == Qt::Key_Return) ||
                 (keyEvent->key() == Qt::Key_Down)) {
            doSearchDown();
            return true;
        } else if (keyEvent->key() == Qt::Key_F3) {
            doSearch(!keyEvent->modifiers().testFlag(Qt::ShiftModifier));
            return true;
        }

//        if ((obj == ui->replaceLineEdit) && (keyEvent->key() == Qt::Key_Tab)
//                && ui->replaceToggleButton->isChecked()) {
//            ui->replaceLineEdit->setFocus();
//        }

        return false;
    }

    return QWidget::eventFilter(obj, event);
}

void QTextEditSearchWidget::searchLineEditTextChanged(const QString &arg1) {
    Q_UNUSED(arg1);
    doSearchDown();
}

void QTextEditSearchWidget::doSearchUp() {
    doSearch(false);
}

void QTextEditSearchWidget::doSearchDown() {
    doSearch(true);
}

bool QTextEditSearchWidget::doReplace(bool forAll) {
    if (_textEdit->isReadOnly()) {
        return false;
    }

    QTextCursor c = _textEdit->textCursor();

    if (!forAll && c.selectedText().isEmpty()) {
        return false;
    }

    int searchMode = ui->modeComboBox->currentIndex();
    if (searchMode == RegularExpressionMode) {
        QString text = c.selectedText();
        text.replace(QRegExp(ui->searchLineEdit->text()),
                             ui->replaceLineEdit->text());
        c.insertText(text);
    } else {
        c.insertText(ui->replaceLineEdit->text());
    }

    if (!forAll) {
        doSearch(true);
    }

    return true;
}

void QTextEditSearchWidget::doReplaceAll() {
    if (_textEdit->isReadOnly()) {
        return;
    }

    // start at the top
    _textEdit->moveCursor(QTextCursor::Start);

    // replace until everything to the bottom is replaced
    while (doSearch(true, false) && doReplace(true)) {}
}

/**
 * @brief Searches for text in the text edit
 */
bool QTextEditSearchWidget::doSearch(bool searchDown, bool allowRestartAtTop) {
    QString text = ui->searchLineEdit->text();

    if (text == "") {
        ui->searchLineEdit->setStyleSheet("* { background: none; }");
        return false;
    }

    int searchMode = ui->modeComboBox->currentIndex();

    QFlags<QTextDocument::FindFlag> options = searchDown ?
                                              QTextDocument::FindFlag(0)
                                              : QTextDocument::FindBackward;
    if (searchMode == WholeWordsMode) {
        options |= QTextDocument::FindWholeWords;
    }

    if (ui->matchCaseSensitiveButton->isChecked()) {
        options |= QTextDocument::FindCaseSensitively;
    }

    bool found;
    if (searchMode == RegularExpressionMode) {
        found = _textEdit->find(QRegExp(text), options);
    } else {
        found = _textEdit->find(text, options);
    }

    // start at the top (or bottom) if not found
    if (!found && allowRestartAtTop) {
        _textEdit->moveCursor(
                searchDown ? QTextCursor::Start : QTextCursor::End);
        found = _textEdit->find(text, options);
    }

    QRect rect = _textEdit->cursorRect();
    QMargins margins = _textEdit->layout()->contentsMargins();
    int searchWidgetHotArea = _textEdit->height() - this->height();
    int marginBottom = (rect.y() > searchWidgetHotArea) ? (this->height() + 10)
                                                        : 0;

    // move the search box a bit up if we would block the search result
    if (margins.bottom() != marginBottom) {
        margins.setBottom(marginBottom);
        _textEdit->layout()->setContentsMargins(margins);
    }

    // add a background color according if we found the text or not
    QString colorCode = found ? "#D5FAE2" : "#FAE9EB";
    ui->searchLineEdit->setStyleSheet("* { background: " + colorCode + "; }");

    return found;
}

<commit_msg>restore the last cursor position if text wasn't found any more<commit_after>/*
 * Copyright (C) 2016 Patrizio Bekerle -- http://www.bekerle.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 * for more details.
 *
 */

#include "qtexteditsearchwidget.h"
#include "ui_qtexteditsearchwidget.h"
#include <QEvent>
#include <QKeyEvent>
#include <QDebug>

QTextEditSearchWidget::QTextEditSearchWidget(QTextEdit *parent) :
    QWidget(parent),
    ui(new Ui::QTextEditSearchWidget)
{
    ui->setupUi(this);
    _textEdit = parent;
    hide();

    QObject::connect(ui->closeButton, SIGNAL(clicked()),
                     this, SLOT(deactivate()));
    QObject::connect(ui->searchLineEdit, SIGNAL(textChanged(const QString &)),
                     this, SLOT(searchLineEditTextChanged(const QString &)));
    QObject::connect(ui->searchDownButton, SIGNAL(clicked()),
                     this, SLOT(doSearchDown()));
    QObject::connect(ui->searchUpButton, SIGNAL(clicked()),
                     this, SLOT(doSearchUp()));
    QObject::connect(ui->replaceToggleButton, SIGNAL(toggled(bool)),
                     this, SLOT(setReplaceMode(bool)));
    QObject::connect(ui->replaceButton, SIGNAL(clicked()),
                     this, SLOT(doReplace()));
    QObject::connect(ui->replaceAllButton, SIGNAL(clicked()),
                     this, SLOT(doReplaceAll()));

    installEventFilter(this);
    ui->searchLineEdit->installEventFilter(this);
    ui->replaceLineEdit->installEventFilter(this);

#ifdef Q_OS_MAC
    // set the spacing to 8 for OS X
    layout()->setSpacing(8);
    ui->buttonFrame->layout()->setSpacing(9);

    // set the margin to 0 for the top buttons for OS X
    QString buttonStyle = "QPushButton {margin: 0}";
    ui->closeButton->setStyleSheet(buttonStyle);
    ui->searchDownButton->setStyleSheet(buttonStyle);
    ui->searchUpButton->setStyleSheet(buttonStyle);
    ui->replaceToggleButton->setStyleSheet(buttonStyle);
    ui->matchCaseSensitiveButton->setStyleSheet(buttonStyle);
#endif
}

QTextEditSearchWidget::~QTextEditSearchWidget() {
    delete ui;
}

void QTextEditSearchWidget::activate() {
    setReplaceMode(false);
    show();
    ui->searchLineEdit->setFocus();
    ui->searchLineEdit->selectAll();
    doSearchDown();
}

void QTextEditSearchWidget::activateReplace() {
    ui->searchLineEdit->setText(_textEdit->textCursor().selectedText());
    ui->searchLineEdit->selectAll();
    activate();
    setReplaceMode(true);
}

void QTextEditSearchWidget::deactivate() {
    hide();
    _textEdit->setFocus();
}

void QTextEditSearchWidget::setReplaceMode(bool enabled) {
    ui->replaceToggleButton->setChecked(enabled);
    ui->replaceLabel->setVisible(enabled);
    ui->replaceLineEdit->setVisible(enabled);
    ui->modeLabel->setVisible(enabled);
    ui->buttonFrame->setVisible(enabled);
    ui->matchCaseSensitiveButton->setVisible(enabled);
}

bool QTextEditSearchWidget::eventFilter(QObject *obj, QEvent *event) {
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);

        if (keyEvent->key() == Qt::Key_Escape) {
            deactivate();
            return true;
        } else if ((keyEvent->modifiers().testFlag(Qt::ShiftModifier) &&
                  (keyEvent->key() == Qt::Key_Return)) ||
                 (keyEvent->key() == Qt::Key_Up)) {
            doSearchUp();
            return true;
        } else if ((keyEvent->key() == Qt::Key_Return) ||
                 (keyEvent->key() == Qt::Key_Down)) {
            doSearchDown();
            return true;
        } else if (keyEvent->key() == Qt::Key_F3) {
            doSearch(!keyEvent->modifiers().testFlag(Qt::ShiftModifier));
            return true;
        }

//        if ((obj == ui->replaceLineEdit) && (keyEvent->key() == Qt::Key_Tab)
//                && ui->replaceToggleButton->isChecked()) {
//            ui->replaceLineEdit->setFocus();
//        }

        return false;
    }

    return QWidget::eventFilter(obj, event);
}

void QTextEditSearchWidget::searchLineEditTextChanged(const QString &arg1) {
    Q_UNUSED(arg1);
    doSearchDown();
}

void QTextEditSearchWidget::doSearchUp() {
    doSearch(false);
}

void QTextEditSearchWidget::doSearchDown() {
    doSearch(true);
}

bool QTextEditSearchWidget::doReplace(bool forAll) {
    if (_textEdit->isReadOnly()) {
        return false;
    }

    QTextCursor c = _textEdit->textCursor();

    if (!forAll && c.selectedText().isEmpty()) {
        return false;
    }

    int searchMode = ui->modeComboBox->currentIndex();
    if (searchMode == RegularExpressionMode) {
        QString text = c.selectedText();
        text.replace(QRegExp(ui->searchLineEdit->text()),
                             ui->replaceLineEdit->text());
        c.insertText(text);
    } else {
        c.insertText(ui->replaceLineEdit->text());
    }

    if (!forAll) {
        int position = c.position();

        if (!doSearch(true)) {
            // restore the last cursor position if text wasn't found any more
            c.setPosition(position);
            _textEdit->setTextCursor(c);
        }
    }

    return true;
}

void QTextEditSearchWidget::doReplaceAll() {
    if (_textEdit->isReadOnly()) {
        return;
    }

    // start at the top
    _textEdit->moveCursor(QTextCursor::Start);

    // replace until everything to the bottom is replaced
    while (doSearch(true, false) && doReplace(true)) {}
}

/**
 * @brief Searches for text in the text edit
 * @returns true if found
 */
bool QTextEditSearchWidget::doSearch(bool searchDown, bool allowRestartAtTop) {
    QString text = ui->searchLineEdit->text();

    if (text == "") {
        ui->searchLineEdit->setStyleSheet("* { background: none; }");
        return false;
    }

    int searchMode = ui->modeComboBox->currentIndex();

    QFlags<QTextDocument::FindFlag> options = searchDown ?
                                              QTextDocument::FindFlag(0)
                                              : QTextDocument::FindBackward;
    if (searchMode == WholeWordsMode) {
        options |= QTextDocument::FindWholeWords;
    }

    if (ui->matchCaseSensitiveButton->isChecked()) {
        options |= QTextDocument::FindCaseSensitively;
    }

    bool found;
    if (searchMode == RegularExpressionMode) {
        found = _textEdit->find(QRegExp(text), options);
    } else {
        found = _textEdit->find(text, options);
    }

    // start at the top (or bottom) if not found
    if (!found && allowRestartAtTop) {
        _textEdit->moveCursor(
                searchDown ? QTextCursor::Start : QTextCursor::End);
        found = _textEdit->find(text, options);
    }

    QRect rect = _textEdit->cursorRect();
    QMargins margins = _textEdit->layout()->contentsMargins();
    int searchWidgetHotArea = _textEdit->height() - this->height();
    int marginBottom = (rect.y() > searchWidgetHotArea) ? (this->height() + 10)
                                                        : 0;

    // move the search box a bit up if we would block the search result
    if (margins.bottom() != marginBottom) {
        margins.setBottom(marginBottom);
        _textEdit->layout()->setContentsMargins(margins);
    }

    // add a background color according if we found the text or not
    QString colorCode = found ? "#D5FAE2" : "#FAE9EB";
    ui->searchLineEdit->setStyleSheet("* { background: " + colorCode + "; }");

    return found;
}

<|endoftext|>


<commit_before>/** \file    add_synonyms.cc
 *  \brief   Generic version for augmenting title data with synonyms found
             in the authority data
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*  We offer a list of tags and subfields where the primary data resides along
    with a list of tags and subfields where the synonym data is found and
    a list of unused fields in the title data where the synonyms can be stored
*/

#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "FileUtil.h"
#include "MarcReader.h"
#include "MarcRecord.h"
#include "MarcWriter.h"
#include "MediaTypeUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

static unsigned modified_count(0);
static unsigned record_count(0);

void Usage() {
    std::cerr << "Usage: " << ::progname << " master_marc_input norm_data_marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

std::string GetTag(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(0, 3);
}

std::string GetSubfieldCodes(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(3);
}

bool FilterPasses(const MarcRecord &record, const std::map<std::string, std::pair<std::string, std::string>> &filter_specs, const std::string &field_spec) {
      auto filter_spec(filter_specs.find(field_spec));
      if (filter_spec == filter_specs.cend())
          return true;

      auto rule(filter_spec->second);
      // We have field_spec in key and rule to match in value
      std::string subfield_codes(GetSubfieldCodes(rule.first));
      if (subfield_codes.length() != 1)
         Error("Invalid subfield specification "  + subfield_codes + " for filter");

      std::string subfield_value;
      if ((subfield_value = record.extractFirstSubfield(GetTag(rule.first), subfield_codes.c_str()[0])).empty())
          return false;

      return subfield_value == rule.second;
}

void ExtractSynonyms(MarcReader * const authority_reader,
                     const std::set<std::string> &primary_tags_and_subfield_codes,
                     const std::set<std::string> &synonym_tags_and_subfield_codes,
                     std::vector<std::map<std::string, std::string>> * const synonym_maps,
                     const std::map<std::string, std::pair<std::string, std::string>> &filter_spec)
{
    while (const MarcRecord record = authority_reader->read()) {
        std::set<std::string>::const_iterator primary;
        std::set<std::string>::const_iterator synonym;
        unsigned int i(0);
        for (primary = primary_tags_and_subfield_codes.begin(), synonym = synonym_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++synonym, ++i)
        {
            // Fill maps with synonyms
            std::vector<std::string> primary_values;
            std::vector<std::string> synonym_values;

            if (FilterPasses(record, filter_spec, *primary) and
                record.extractSubfields(GetTag(*primary), GetSubfieldCodes(*primary), &primary_values) and
                record.extractSubfields(GetTag(*synonym), GetSubfieldCodes(*synonym), &synonym_values))
                    (*synonym_maps)[i].emplace(StringUtil::Join(primary_values, ','),
                                               StringUtil::Join(synonym_values, ','));
        }
    }
}

inline std::string GetMapValueOrEmptyString(const std::map<std::string, std::string> &map,
                                            const std::string &searchterm)
{
    auto value(map.find(searchterm));
    return (value != map.cend()) ? value->second : "";
}

void ProcessRecord(MarcRecord * const record, const std::vector<std::map<std::string, std::string>> &synonym_maps,
                   const std::set<std::string> &primary_tags_and_subfield_codes,
                   const std::set<std::string> &output_tags_and_subfield_codes)
{
    std::set<std::string>::const_iterator primary;
    std::set<std::string>::const_iterator output;
    unsigned int i(0);

    if (primary_tags_and_subfield_codes.size() == output_tags_and_subfield_codes.size()) {
        for (primary = primary_tags_and_subfield_codes.begin(), output = output_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++output, ++i)
        {
            std::vector<std::string> primary_values;
            std::set<std::string> synonym_values;
            std::vector<size_t> field_indices;
            if (record->getFieldIndices(GetTag(*primary), &field_indices) != MarcRecord::FIELD_NOT_FOUND) {
                for (auto field_index : field_indices) {
                     primary_values.clear();
                     if (record->getSubfields(field_index).extractSubfields(GetSubfieldCodes(*primary), &primary_values)) {
                        std::string searchterm = StringUtil::Join(primary_values, ',');
                        // First case: Look up synonyms only in one category
                        if (i < synonym_maps.size()) {
                            const auto &synonym_map(synonym_maps[i]);
                            const auto &synonym(GetMapValueOrEmptyString(synonym_map, searchterm));
                            if (not synonym.empty())
                                synonym_values.insert(synonym);
                        }

                        // Second case: Look up synonyms in all categories
                        else {
                            for (auto &synonym_map : synonym_maps) {
                                const auto &synonym(GetMapValueOrEmptyString(synonym_map, searchterm));
                                if (not synonym.empty())
                                   synonym_values.insert(synonym);
                            }
                        }
                    }
                 }

                if (synonym_values.empty())
                     continue;

                const std::string synonyms(StringUtil::Join(synonym_values, ','));

                // Insert synonyms
                // Abort if field is already populated
                std::string tag(GetTag(*output));
                if (record->getFieldIndex(tag) != MarcRecord::FIELD_NOT_FOUND)
                    Error("Field with tag " + tag + " is not empty for PPN " + record->getControlNumber() + '\n');
                std::string subfield_spec = GetSubfieldCodes(*output);
                if (unlikely(subfield_spec.size() != 1))
                    Error("We currently only support a single subfield and thus specifying " + subfield_spec
                          + " as output subfield is not valid\n");
                Subfields subfields(' ', ' '); // <- indicators must be set explicitly although empty
                subfields.addSubfield(subfield_spec.at(0), synonyms);
                if (not(record->insertField(tag, subfields.toString())))
                    Warning("Could not insert field " + tag + " for PPN " + record->getControlNumber() + '\n');
                ++modified_count;
            }
        }
    }
}

void InsertSynonyms(MarcReader * const marc_reader, MarcWriter * const marc_writer,
                    const std::set<std::string> &primary_tags_and_subfield_codes,
                    const std::set<std::string> &output_tags_and_subfield_codes,
                    std::vector<std::map<std::string, std::string>> &synonym_maps)
{
    while (MarcRecord record = marc_reader->read()) {
        ProcessRecord(&record, synonym_maps, primary_tags_and_subfield_codes, output_tags_and_subfield_codes);
        marc_writer->write(record);
        ++record_count;
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " record(s).\n";
}

int ParseSpec(std::string spec_str, std::set<std::string> * const field_specs, std::map<std::string, std::pair<std::string, std::string>> * filter_specs = nullptr) {
    std::set<std::string> raw_field_specs;

    if (unlikely(StringUtil::Split(spec_str, ':', &raw_field_specs) < 1)) {
        Error("Need at least one field");
        return -1;
    }

    if (filter_specs == nullptr) {
        *field_specs = raw_field_specs;
	return 0;
    }

    // Iterate over all Field-specs and extract possible filters
    static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory("(\\d{1,3}[a-z]+)\\[(\\d{1,3}[a-z])=(.*)\\]"));

    for (auto field_spec : raw_field_specs) {
        if (matcher->matched(field_spec)) {
            filter_specs->emplace((*matcher)[1], std::make_pair((*matcher)[2], (*matcher)[3]));
            auto bracket = field_spec.find("[");
            field_spec = (bracket != std::string::npos) ? field_spec.erase(bracket, field_spec.length()) : field_spec;
        }
        field_specs->insert(field_spec);
    }
    return 0;
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 4)
        Usage();

    const std::string marc_input_filename(argv[1]);
    const std::string authority_data_marc_input_filename(argv[2]);
    const std::string marc_output_filename(argv[3]);
    if (unlikely(marc_input_filename == marc_output_filename))
        Error("Title data input file name equals output file name!");
    if (unlikely(authority_data_marc_input_filename == marc_output_filename))
        Error("Authority data input file name equals output file name!");

    std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(marc_input_filename, MarcReader::BINARY));
    std::unique_ptr<MarcReader> authority_reader(MarcReader::Factory(authority_data_marc_input_filename,
                                                                     MarcReader::BINARY));
    std::unique_ptr<MarcWriter> marc_writer(MarcWriter::Factory(marc_output_filename, MarcWriter::BINARY));

    try {
        // Determine possible mappings
        // Values in square brackets specify a positive criterion for values to be taken into account
        const std::string AUTHORITY_DATA_PRIMARY_SPEC("100abcd[079v=piz]:110abcd:111abcd:130abcd:150abcd:151abcd");
        const std::string AUTHORITY_DATA_SYNONYM_SPEC("400abcd:410abcd:411abcd:430abcd:450abcd:451abcd");
        const std::string TITLE_DATA_PRIMARY_SPEC("600abcd:610abcd:611abcd:630abcd:650abcd:651abcd:689abcd");
        const std::string TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS("180a:181a:182a:183a:184a:185a:186a");

        // Determine fields to handle
        std::set<std::string> primary_tags_and_subfield_codes;
        std::set<std::string> synonym_tags_and_subfield_codes;
        std::set<std::string> input_tags_and_subfield_codes;
        std::set<std::string> output_tags_and_subfield_codes;

        std::map<std::string, std::pair<std::string, std::string>> filter_specs;

        if (unlikely(ParseSpec(AUTHORITY_DATA_PRIMARY_SPEC, &primary_tags_and_subfield_codes, &filter_specs) < 0))
            Error("Could not properly parse " + AUTHORITY_DATA_PRIMARY_SPEC);

        if (unlikely(StringUtil::Split(AUTHORITY_DATA_SYNONYM_SPEC, ":", &synonym_tags_and_subfield_codes) == 0))
            Error("Need at least one synonym field");

        if (unlikely(StringUtil::Split(TITLE_DATA_PRIMARY_SPEC, ":", &input_tags_and_subfield_codes) == 0))
            Error("Need at least one input field");

        if (unlikely(StringUtil::Split(TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS, ":", &output_tags_and_subfield_codes)
                     == 0))
            Error("Need at least one output field");

        unsigned num_of_authority_entries(primary_tags_and_subfield_codes.size());

        if (synonym_tags_and_subfield_codes.size() != num_of_authority_entries)
            Error("Number of authority primary specs must match number of synonym specs");
        if (input_tags_and_subfield_codes.size() != output_tags_and_subfield_codes.size())
            Error("Number of fields title entry specs must match number of output specs");

        std::vector<std::map<std::string, std::string>> synonym_maps(num_of_authority_entries,
                                                                     std::map<std::string, std::string>());

        // Extract the synonyms from authority data
        ExtractSynonyms(authority_reader.get(), primary_tags_and_subfield_codes, synonym_tags_and_subfield_codes,
                        &synonym_maps, filter_specs);

        // Iterate over the title data
        InsertSynonyms(marc_reader.get(), marc_writer.get(), input_tags_and_subfield_codes,
                       output_tags_and_subfield_codes, synonym_maps);

    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Required changes<commit_after>/** \file    add_synonyms.cc
 *  \brief   Generic version for augmenting title data with synonyms found
             in the authority data
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*  We offer a list of tags and subfields where the primary data resides along
    with a list of tags and subfields where the synonym data is found and
    a list of unused fields in the title data where the synonyms can be stored
*/

#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "FileUtil.h"
#include "MarcReader.h"
#include "MarcRecord.h"
#include "MarcWriter.h"
#include "MediaTypeUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

static unsigned modified_count(0);
static unsigned record_count(0);

void Usage() {
    std::cerr << "Usage: " << ::progname << " master_marc_input norm_data_marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

std::string GetTag(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(0, 3);
}

std::string GetSubfieldCodes(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(3);
}

bool FilterPasses(const MarcRecord &record, const std::map<std::string, std::pair<std::string, std::string>> &filter_specs, const std::string &field_spec) {
      auto filter_spec(filter_specs.find(field_spec));
      if (filter_spec == filter_specs.cend())
          return true;

      auto rule(filter_spec->second);
      // We have field_spec in key and rule to match in value
      std::string subfield_codes(GetSubfieldCodes(rule.first));
      if (subfield_codes.length() != 1)
         Error("Invalid subfield specification "  + subfield_codes + " for filter");

      std::string subfield_value;
      if ((subfield_value = record.extractFirstSubfield(GetTag(rule.first), subfield_codes.c_str()[0])).empty())
          return false;

      return subfield_value == rule.second;
}

void ExtractSynonyms(MarcReader * const authority_reader,
                     const std::set<std::string> &primary_tags_and_subfield_codes,
                     const std::set<std::string> &synonym_tags_and_subfield_codes,
                     std::vector<std::map<std::string, std::string>> * const synonym_maps,
                     const std::map<std::string, std::pair<std::string, std::string>> &filter_spec)
{
    while (const MarcRecord record = authority_reader->read()) {
        std::set<std::string>::const_iterator primary;
        std::set<std::string>::const_iterator synonym;
        unsigned int i(0);
        for (primary = primary_tags_and_subfield_codes.begin(), synonym = synonym_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++synonym, ++i)
        {
            // Fill maps with synonyms
            std::vector<std::string> primary_values;
            std::vector<std::string> synonym_values;

            if (FilterPasses(record, filter_spec, *primary) and
                record.extractSubfields(GetTag(*primary), GetSubfieldCodes(*primary), &primary_values) and
                record.extractSubfields(GetTag(*synonym), GetSubfieldCodes(*synonym), &synonym_values))
                    (*synonym_maps)[i].emplace(StringUtil::Join(primary_values, ','),
                                               StringUtil::Join(synonym_values, ','));
        }
    }
}

inline std::string GetMapValueOrEmptyString(const std::map<std::string, std::string> &map,
                                            const std::string &searchterm)
{
    auto value(map.find(searchterm));
    return (value != map.cend()) ? value->second : "";
}

void ProcessRecord(MarcRecord * const record, const std::vector<std::map<std::string, std::string>> &synonym_maps,
                   const std::set<std::string> &primary_tags_and_subfield_codes,
                   const std::set<std::string> &output_tags_and_subfield_codes)
{
    std::set<std::string>::const_iterator primary;
    std::set<std::string>::const_iterator output;
    unsigned int i(0);

    if (primary_tags_and_subfield_codes.size() == output_tags_and_subfield_codes.size()) {
        for (primary = primary_tags_and_subfield_codes.begin(), output = output_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++output, ++i)
        {
            std::vector<std::string> primary_values;
            std::set<std::string> synonym_values;
            std::vector<size_t> field_indices;
            if (record->getFieldIndices(GetTag(*primary), &field_indices) != MarcRecord::FIELD_NOT_FOUND) {
                for (auto field_index : field_indices) {
                     primary_values.clear();
                     if (record->getSubfields(field_index).extractSubfields(GetSubfieldCodes(*primary), &primary_values)) {
                        std::string searchterm = StringUtil::Join(primary_values, ',');
                        // First case: Look up synonyms only in one category
                        if (i < synonym_maps.size()) {
                            const auto &synonym_map(synonym_maps[i]);
                            const auto &synonym(GetMapValueOrEmptyString(synonym_map, searchterm));
                            if (not synonym.empty())
                                synonym_values.insert(synonym);
                        }

                        // Second case: Look up synonyms in all categories
                        else {
                            for (auto &synonym_map : synonym_maps) {
                                const auto &synonym(GetMapValueOrEmptyString(synonym_map, searchterm));
                                if (not synonym.empty())
                                   synonym_values.insert(synonym);
                            }
                        }
                    }
                 }

                if (synonym_values.empty())
                     continue;

                const std::string synonyms(StringUtil::Join(synonym_values, ','));

                // Insert synonyms
                // Abort if field is already populated
                std::string tag(GetTag(*output));
                if (record->getFieldIndex(tag) != MarcRecord::FIELD_NOT_FOUND)
                    Error("Field with tag " + tag + " is not empty for PPN " + record->getControlNumber() + '\n');
                std::string subfield_spec = GetSubfieldCodes(*output);
                if (unlikely(subfield_spec.size() != 1))
                    Error("We currently only support a single subfield and thus specifying " + subfield_spec
                          + " as output subfield is not valid\n");
                Subfields subfields(' ', ' '); // <- indicators must be set explicitly although empty
                subfields.addSubfield(subfield_spec.at(0), synonyms);
                if (not(record->insertField(tag, subfields.toString())))
                    Warning("Could not insert field " + tag + " for PPN " + record->getControlNumber() + '\n');
                ++modified_count;
            }
        }
    }
}

void InsertSynonyms(MarcReader * const marc_reader, MarcWriter * const marc_writer,
                    const std::set<std::string> &primary_tags_and_subfield_codes,
                    const std::set<std::string> &output_tags_and_subfield_codes,
                    std::vector<std::map<std::string, std::string>> &synonym_maps)
{
    while (MarcRecord record = marc_reader->read()) {
        ProcessRecord(&record, synonym_maps, primary_tags_and_subfield_codes, output_tags_and_subfield_codes);
        marc_writer->write(record);
        ++record_count;
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " record(s).\n";
}

bool ParseSpec(std::string spec_str, std::set<std::string> * const field_specs, std::map<std::string, std::pair<std::string, std::string>> * filter_specs = nullptr) {
    std::set<std::string> raw_field_specs;

    if (unlikely(StringUtil::Split(spec_str, ':', &raw_field_specs) < 1)) {
        Error("Need at least one field");
        return false;
    }

    if (filter_specs == nullptr) {
        *field_specs = raw_field_specs;
	return true;
    }

    // Iterate over all Field-specs and extract possible filters
    static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory("(\\d{1,3}[a-z]+)\\[(\\d{1,3}[a-z])=(.*)\\]"));

    for (auto field_spec : raw_field_specs) {
        if (matcher->matched(field_spec)) {
            filter_specs->emplace((*matcher)[1], std::make_pair((*matcher)[2], (*matcher)[3]));
            auto bracket = field_spec.find("[");
            field_spec = (bracket != std::string::npos) ? field_spec.erase(bracket, field_spec.length()) : field_spec;
        }
        field_specs->insert(field_spec);
    }
    return true;
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 4)
        Usage();

    const std::string marc_input_filename(argv[1]);
    const std::string authority_data_marc_input_filename(argv[2]);
    const std::string marc_output_filename(argv[3]);
    if (unlikely(marc_input_filename == marc_output_filename))
        Error("Title data input file name equals output file name!");
    if (unlikely(authority_data_marc_input_filename == marc_output_filename))
        Error("Authority data input file name equals output file name!");

    std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(marc_input_filename, MarcReader::BINARY));
    std::unique_ptr<MarcReader> authority_reader(MarcReader::Factory(authority_data_marc_input_filename,
                                                                     MarcReader::BINARY));
    std::unique_ptr<MarcWriter> marc_writer(MarcWriter::Factory(marc_output_filename, MarcWriter::BINARY));

    try {
        // Determine possible mappings
        // Values in square brackets specify a positive criterion for values to be taken into account
        const std::string AUTHORITY_DATA_PRIMARY_SPEC("100abcd[079v=piz]:110abcd:111abcd:130abcd:150abcd:151abcd");
        const std::string AUTHORITY_DATA_SYNONYM_SPEC("400abcd:410abcd:411abcd:430abcd:450abcd:451abcd");
        const std::string TITLE_DATA_PRIMARY_SPEC("600abcd:610abcd:611abcd:630abcd:650abcd:651abcd:689abcd");
        const std::string TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS("180a:181a:182a:183a:184a:185a:186a");

        // Determine fields to handle
        std::set<std::string> primary_tags_and_subfield_codes;
        std::set<std::string> synonym_tags_and_subfield_codes;
        std::set<std::string> input_tags_and_subfield_codes;
        std::set<std::string> output_tags_and_subfield_codes;

        std::map<std::string, std::pair<std::string, std::string>> filter_specs;

        if (unlikely(ParseSpec(AUTHORITY_DATA_PRIMARY_SPEC, &primary_tags_and_subfield_codes, &filter_specs) < 0))
            Error("Could not properly parse " + AUTHORITY_DATA_PRIMARY_SPEC);

        if (unlikely(StringUtil::Split(AUTHORITY_DATA_SYNONYM_SPEC, ":", &synonym_tags_and_subfield_codes) == 0))
            Error("Need at least one synonym field");

        if (unlikely(StringUtil::Split(TITLE_DATA_PRIMARY_SPEC, ":", &input_tags_and_subfield_codes) == 0))
            Error("Need at least one input field");

        if (unlikely(StringUtil::Split(TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS, ":", &output_tags_and_subfield_codes)
                     == 0))
            Error("Need at least one output field");

        unsigned num_of_authority_entries(primary_tags_and_subfield_codes.size());

        if (synonym_tags_and_subfield_codes.size() != num_of_authority_entries)
            Error("Number of authority primary specs must match number of synonym specs");
        if (input_tags_and_subfield_codes.size() != output_tags_and_subfield_codes.size())
            Error("Number of fields title entry specs must match number of output specs");

        std::vector<std::map<std::string, std::string>> synonym_maps(num_of_authority_entries,
                                                                     std::map<std::string, std::string>());

        // Extract the synonyms from authority data
        ExtractSynonyms(authority_reader.get(), primary_tags_and_subfield_codes, synonym_tags_and_subfield_codes,
                        &synonym_maps, filter_specs);

        // Iterate over the title data
        InsertSynonyms(marc_reader.get(), marc_writer.get(), input_tags_and_subfield_codes,
                       output_tags_and_subfield_codes, synonym_maps);

    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>#include <chrono>
#include <ctime>
#include <fstream>
#include <iostream>
#include <map>
#include <queue>
#include <ratio>
#include <string>
#include <stdlib.h>
#include <time.h>
#include<sys/time.h>
#include "omp.h"
#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include "boost/lexical_cast.hpp"

using namespace boost::algorithm;

#include "pass_runner.h"

#define NUM_THREADS 8 // default number of threads
#define MAX_NUM_PER_THREAD 1
#define RERUN_COUNT 10
#define MAX_PASS_LENGTH 10

#if(0)
#ifdef DEBUG
#ifndef TIME
#define TIME
#endif
#endif
#endif

using namespace std;
using namespace std::chrono;

/*------- GLOBAL VARIABES --------*/
// vector with permutations of passorder
vector<string> passOrder;
char *binaryName;
char *binaryArgs;
char *input_combination_file;
string dir_name;

struct timeval start, end_time;

#define _SYSTEM_CALL( CMD ) ( {            \
    int err = ( system( CMD.c_str() ) );   \
    if ( err < 0  ) {                      \
        fprintf(stderr, #CMD, " failed."); \
        abort();                           \
    }                                      \
    err;                                   \
})                                         \

inline COMMAND::COMMAND(string pass_order, long double threadId) {
  // opt -pass1 -pass2 ./bcfile -o temp.out.threadId >> /dev/null

  // combination_file_name/temp.out.input_combination_filename
  string temp_name = dir_name + string("./temp.out") + to_string(threadId); //+ input_combination_file;

  opt = string("opt ") + pass_order + " ./"  + binaryName + " -o "+ temp_name  + "" + " >> /dev/null";
  // Command to execute the file.
  lli = string("lli ") + temp_name + " " + binaryArgs;
}

struct passTime
{
  string pass_name;
  double time;
};

class PassTimeComparator
{
  public:
    bool operator()(passTime& n1, passTime& n2)
    {
      if (n1.time > n2.time)
        return true;
      else
        return false;
    }
};

void cleanUpTheMess() {
  string rm_command = string("rm -rf ") + dir_name;

#ifdef DEBUG
  cout << "Cleaning temporary files.." << endl;
  cout << "Running Command: " << rm_command << endl;
#endif
  _SYSTEM_CALL ( rm_command) ;
}

vector<string>& getOptimizationPasses() {
  vector<string> *optimizationPasses = new vector<string>();
  for(std::map<int, std::string>::iterator it = A::PASS_MAP.begin(), ie = A::PASS_MAP.end(); ie != it; ++it) {
    optimizationPasses->push_back(it->second);
  }
  return *optimizationPasses;
}

void runOptimizationPasses() {
  //map<string, double> optExecMap;
  std::map<string, long> after_pass_time;

  vector<string> &optimizationPasses = getOptimizationPasses();

  clock_t t1,t2;
  std::chrono::time_point<std::chrono::system_clock> start, end;
  float diff;
  long double tid;
  string pass_name;
  int pass_length = 0;
  string curr_pass_order = string("");
  while(pass_length < MAX_PASS_LENGTH) {
    priority_queue< passTime, vector< passTime >, PassTimeComparator> curr_pq;
#pragma omp parallel for private(pass_name, tid)
    for( int i = 0; i < optimizationPasses.size() ; ++i ) {
      pass_name = optimizationPasses[i];
      string temp_pass_order = curr_pass_order + string(" ") + pass_name;
      std::cout << pass_name << std::endl;
      tid = omp_get_thread_num();
      // apply pass here
      COMMAND Cmd(temp_pass_order, tid);
      _SYSTEM_CALL(Cmd.opt);

      // run RERUN_COUNT number of times to get the time
        // START TIMER HERE
       start = std::chrono::system_clock::now();
      for(int j=0; j < RERUN_COUNT; j++) {
      	_SYSTEM_CALL(Cmd.lli);
      }
      end = std::chrono::system_clock::now();
      std::chrono::duration<double> elapsed_seconds = end-start;
      double time_taken_by_current_pass = elapsed_seconds.count();
      // STOP TIMER HERE
#ifdef DEBUG
      cout << "Running Command: " << Cmd.opt  << "time taken " << time_taken_by_current_pass << endl;
#endif
      // store the time taken by current pass
      passTime curr = {pass_name, time_taken_by_current_pass};
      curr_pq.push(curr);
    }

    passTime pt = curr_pq.top();

    curr_pass_order = curr_pass_order + string(" ") + pt.pass_name;

    cout << "Appending " << pt.pass_name << " | Current Pass Order " << curr_pass_order << endl;
    pass_length++;
  }

  cleanUpTheMess();
}

int main(int argc, char** argv) {

  int numThreads = NUM_THREADS;

  if(argc > 1) {
    binaryName = argv[1];
    binaryArgs = argv[2];
    numThreads = atoi(argv[3]);

    std::cout << binaryName << " " << binaryArgs << " " << numThreads << " " << endl;//<< input_combination_file << endl;
  } else {
    std::cout << "Usage: pass_runner <Binary Name> <NumThreads(optional)>" << std::endl;
    abort();
  }

  // set openmp number of threads
  omp_set_num_threads(numThreads);

//dir_name = string(input_combination_file) + "dir";
  //string create_dir_cmd = string("mkdir ") + dir_name;
  //_SYSTEM_CALL(create_dir_cmd );

  runOptimizationPasses();

  return EXIT_SUCCESS;
}
<commit_msg>adding markov<commit_after>#include <chrono>
#include <ctime>
#include <fstream>
#include <iostream>
#include <map>
#include <queue>
#include <ratio>
#include <string>
#include <stdlib.h>
#include <time.h>
#include<sys/time.h>
#include "omp.h"
#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include "boost/lexical_cast.hpp"

using namespace boost::algorithm;

#include "pass_runner.h"

#define NUM_THREADS 8 // default number of threads
#define MAX_NUM_PER_THREAD 1
#define RERUN_COUNT 10
#define MAX_PASS_LENGTH 10

#if(0)
#ifdef DEBUG
#ifndef TIME
#define TIME
#endif
#endif
#endif

using namespace std;
using namespace std::chrono;

/*------- GLOBAL VARIABES --------*/
// vector with permutations of passorder
vector<string> passOrder;
char *binaryName;
char *binaryArgs;
char *input_combination_file;
string dir_name;

struct timeval start, end_time;

#define _SYSTEM_CALL( CMD ) ( {            \
    int err = ( system( CMD.c_str() ) );   \
    if ( err < 0  ) {                      \
        fprintf(stderr, #CMD, " failed."); \
        abort();                           \
    }                                      \
    err;                                   \
})                                         \

inline COMMAND::COMMAND(string pass_order, long double threadId) {
  // opt -pass1 -pass2 ./bcfile -o temp.out.threadId >> /dev/null

  // combination_file_name/temp.out.input_combination_filename
  string temp_name = dir_name + string("./temp.out") + to_string(threadId); //+ input_combination_file;

  opt = string("opt ") + pass_order + " ./"  + binaryName + " -o "+ temp_name  + "" + " >> /dev/null";
  // Command to execute the file.
  lli = string("lli ") + temp_name + " " + binaryArgs;
}

struct passTime
{
  string pass_name;
  double time;
};

class PassTimeComparator
{
  public:
    bool operator()(passTime& n1, passTime& n2)
    {
      if (n1.time > n2.time)
        return true;
      else
        return false;
    }
};

void cleanUpTheMess() {
  string rm_command = string("rm -rf ") + dir_name;

#ifdef DEBUG
  cout << "Cleaning temporary files.." << endl;
  cout << "Running Command: " << rm_command << endl;
#endif
  _SYSTEM_CALL ( rm_command) ;
}

vector<string>& getOptimizationPasses() {
  vector<string> *optimizationPasses = new vector<string>();
  for(std::map<int, std::string>::iterator it = A::PASS_MAP.begin(), ie = A::PASS_MAP.end(); ie != it; ++it) {
    optimizationPasses->push_back(it->second);
  }
  return *optimizationPasses;
}

void runOptimizationPasses() {
  //map<string, double> optExecMap;
  std::map<string, long> after_pass_time;

  vector<string> &optimizationPasses = getOptimizationPasses();

  clock_t t1,t2;
  std::chrono::time_point<std::chrono::system_clock> start, end;
  float diff;
  long double tid;
  string pass_name;
  int pass_length = 0;
  string curr_pass_order = string("");
  while(pass_length < MAX_PASS_LENGTH) {
    priority_queue< passTime, vector< passTime >, PassTimeComparator> curr_pq;
#pragma omp parallel for private(pass_name, tid)
    for( int i = 0; i < optimizationPasses.size() ; ++i ) {
      pass_name = optimizationPasses[i];
      string temp_pass_order = curr_pass_order + string(" ") + pass_name;
      std::cout << pass_name << std::endl;
      tid = omp_get_thread_num();
      // apply pass here
      COMMAND Cmd(temp_pass_order, tid);
      _SYSTEM_CALL(Cmd.opt);

      // run RERUN_COUNT number of times to get the time
        // START TIMER HERE
       start = std::chrono::system_clock::now();
      for(int j=0; j < RERUN_COUNT; j++) {
      	_SYSTEM_CALL(Cmd.lli);
      }
      end = std::chrono::system_clock::now();
      std::chrono::duration<double> elapsed_seconds = end-start;
      double time_taken_by_current_pass = elapsed_seconds.count();
      // STOP TIMER HERE
#ifdef DEBUG
      cout << "Running Command: " << Cmd.opt  << "time taken " << time_taken_by_current_pass << endl;
#endif
      // store the time taken by current pass
      passTime curr = {pass_name, time_taken_by_current_pass};
      curr_pq.push(curr);
    }

    passTime pt = curr_pq.top();

    curr_pass_order = curr_pass_order + string(" ") + pt.pass_name;

    cout << "Appending " << pt.pass_name << " | Current Pass Order " << curr_pass_order  << " PassTime " << pt.time << endl;
    pass_length++;
  }

  cleanUpTheMess();
}

int main(int argc, char** argv) {

  int numThreads = NUM_THREADS;

  if(argc > 1) {
    binaryName = argv[1];
    binaryArgs = argv[2];
    numThreads = atoi(argv[3]);

    std::cout << binaryName << " " << binaryArgs << " " << numThreads << " " << endl;//<< input_combination_file << endl;
  } else {
    std::cout << "Usage: pass_runner <Binary Name> <NumThreads(optional)>" << std::endl;
    abort();
  }

  // set openmp number of threads
  omp_set_num_threads(numThreads);

//dir_name = string(input_combination_file) + "dir";
  //string create_dir_cmd = string("mkdir ") + dir_name;
  //_SYSTEM_CALL(create_dir_cmd );

  runOptimizationPasses();

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
* Copyright (C) 2012 David Edmundson <kde@davidedmundson.co.uk>
*
* 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 St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "contact.h"

#include <TelepathyQt/ContactManager>
#include <TelepathyQt/Connection>
#include <TelepathyQt/ContactCapabilities>
#include <TelepathyQt/AvatarData>

#include <QBitmap>
#include <QPixmap>
#include <QPixmapCache>

#include <KIconLoader>

#include "capabilities-hack-private.h"

KTp::Contact::Contact(Tp::ContactManager *manager, const Tp::ReferencedHandles &handle, const Tp::Features &requestedFeatures, const QVariantMap &attributes)
    : Tp::Contact(manager, handle, requestedFeatures, attributes)
{
    connect(manager->connection().data(), SIGNAL(destroyed()), SIGNAL(invalidated()));
    connect(manager->connection().data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SIGNAL(invalidated()));
}

KTp::Presence KTp::Contact::presence() const
{
    return KTp::Presence(Tp::Contact::presence());
}

bool KTp::Contact::audioCallCapability() const
{
    if (! manager()->connection()) {
        return false;
    }
    Tp::ConnectionPtr connection = manager()->connection();
    if (connection) {
        bool contactCanStreamAudio = CapabilitiesHackPrivate::audioCalls(
                                         capabilities(), connection->cmName());
        bool selfCanStreamAudio = CapabilitiesHackPrivate::audioCalls(
                                      connection->selfContact()->capabilities(), connection->cmName());
        return contactCanStreamAudio && selfCanStreamAudio;
    }
    return false;
}

bool KTp::Contact::videoCallCapability() const
{
    if (! manager()->connection()) {
        return false;
    }
    Tp::ConnectionPtr connection = manager()->connection();
    if (connection) {
        bool contactCanStreamVideo = CapabilitiesHackPrivate::videoCalls(
                                         capabilities(), connection->cmName());
        bool selfCanStreamVideo = CapabilitiesHackPrivate::videoCalls(
                                      connection->selfContact()->capabilities(), connection->cmName());
        return contactCanStreamVideo && selfCanStreamVideo;
    }

    return false;
}

bool KTp::Contact::fileTransferCapability()  const
{
    if (! manager()->connection()) {
        return false;
    }
    if (manager()->connection()) {
        bool contactCanHandleFiles = capabilities().fileTransfers();
        bool selfCanHandleFiles = manager()->connection()->selfContact()->capabilities().fileTransfers();
        return contactCanHandleFiles && selfCanHandleFiles;
    }

    return false;
}

QStringList KTp::Contact::clientTypes() const
{
    /* Temporary workaround for upstream bug https://bugs.freedesktop.org/show_bug.cgi?id=55883)
     * Close https://bugs.kde.org/show_bug.cgi?id=308217 when fixed upstream */
    if (Tp::Contact::presence().type() == Tp::ConnectionPresenceTypeOffline) {
        return QStringList();
    }

    return Tp::Contact::clientTypes();
}

QPixmap KTp::Contact::avatarPixmap()
{
    QPixmap avatar;
    QString file = avatarData().fileName;
    if (file.isEmpty()) {
        avatar = KIconLoader::global()->loadIcon(QLatin1String("im-user"), KIconLoader::NoGroup, 96);
    } else {
        avatar.load(file);
    }
    if (presence().type() == Tp::ConnectionPresenceTypeOffline) {
        if (!QPixmapCache::find(keyCache(),avatar)){
            avatarToGray(avatar);
            QPixmapCache::insert(keyCache(), avatar);
        }
    }
    return avatar;
}

void KTp::Contact::avatarToGray(QPixmap &avatar)
{
    QImage image = avatar.toImage();
    QBitmap alphaMask = avatar.mask();
    for (int i = 0; i < image.width(); ++i) {
        for (int j = 0; j < image.height(); ++j) {
            int colour = qGray(image.pixel(i, j));
            image.setPixel(i, j, qRgb(colour, colour, colour));
        }
    }
    avatar = avatar.fromImage(image);
    avatar.setMask(alphaMask);
}

QString KTp::Contact::keyCache() const
{
    return avatarToken()+QLatin1String("-offline");
}

<commit_msg>fixes bad quality gray avatars BUG: 316109 REVIEW: 109279<commit_after>/*
* Copyright (C) 2012 David Edmundson <kde@davidedmundson.co.uk>
*
* 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 St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "contact.h"

#include <TelepathyQt/ContactManager>
#include <TelepathyQt/Connection>
#include <TelepathyQt/ContactCapabilities>
#include <TelepathyQt/AvatarData>

#include <QBitmap>
#include <QPixmap>
#include <QPixmapCache>

#include <KIconLoader>

#include "capabilities-hack-private.h"

KTp::Contact::Contact(Tp::ContactManager *manager, const Tp::ReferencedHandles &handle, const Tp::Features &requestedFeatures, const QVariantMap &attributes)
    : Tp::Contact(manager, handle, requestedFeatures, attributes)
{
    connect(manager->connection().data(), SIGNAL(destroyed()), SIGNAL(invalidated()));
    connect(manager->connection().data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SIGNAL(invalidated()));
}

KTp::Presence KTp::Contact::presence() const
{
    return KTp::Presence(Tp::Contact::presence());
}

bool KTp::Contact::audioCallCapability() const
{
    if (! manager()->connection()) {
        return false;
    }
    Tp::ConnectionPtr connection = manager()->connection();
    if (connection) {
        bool contactCanStreamAudio = CapabilitiesHackPrivate::audioCalls(
                                         capabilities(), connection->cmName());
        bool selfCanStreamAudio = CapabilitiesHackPrivate::audioCalls(
                                      connection->selfContact()->capabilities(), connection->cmName());
        return contactCanStreamAudio && selfCanStreamAudio;
    }
    return false;
}

bool KTp::Contact::videoCallCapability() const
{
    if (! manager()->connection()) {
        return false;
    }
    Tp::ConnectionPtr connection = manager()->connection();
    if (connection) {
        bool contactCanStreamVideo = CapabilitiesHackPrivate::videoCalls(
                                         capabilities(), connection->cmName());
        bool selfCanStreamVideo = CapabilitiesHackPrivate::videoCalls(
                                      connection->selfContact()->capabilities(), connection->cmName());
        return contactCanStreamVideo && selfCanStreamVideo;
    }

    return false;
}

bool KTp::Contact::fileTransferCapability()  const
{
    if (! manager()->connection()) {
        return false;
    }
    if (manager()->connection()) {
        bool contactCanHandleFiles = capabilities().fileTransfers();
        bool selfCanHandleFiles = manager()->connection()->selfContact()->capabilities().fileTransfers();
        return contactCanHandleFiles && selfCanHandleFiles;
    }

    return false;
}

QStringList KTp::Contact::clientTypes() const
{
    /* Temporary workaround for upstream bug https://bugs.freedesktop.org/show_bug.cgi?id=55883)
     * Close https://bugs.kde.org/show_bug.cgi?id=308217 when fixed upstream */
    if (Tp::Contact::presence().type() == Tp::ConnectionPresenceTypeOffline) {
        return QStringList();
    }

    return Tp::Contact::clientTypes();
}

QPixmap KTp::Contact::avatarPixmap()
{
    QPixmap avatar;
    QString file = avatarData().fileName;
    if (file.isEmpty()) {
        avatar = KIconLoader::global()->loadIcon(QLatin1String("im-user"), KIconLoader::NoGroup, 96);
    } else {
        avatar.load(file);
    }
    if (presence().type() == Tp::ConnectionPresenceTypeOffline) {
        if (!QPixmapCache::find(keyCache(),avatar)){
            avatarToGray(avatar);
            QPixmapCache::insert(keyCache(), avatar);
        }
    }
    return avatar;
}

void KTp::Contact::avatarToGray(QPixmap &avatar)
{
    QImage image = avatar.toImage();
    QPixmap alpha= avatar.alphaChannel();
    for (int i = 0; i < image.width(); ++i) {
        for (int j = 0; j < image.height(); ++j) {
            int colour = qGray(image.pixel(i, j));
            image.setPixel(i, j, qRgb(colour, colour, colour));
        }
    }
    avatar = avatar.fromImage(image);
    avatar.setAlphaChannel(alpha);
}

QString KTp::Contact::keyCache() const
{
    return avatarToken()+QLatin1String("-offline");
}

<|endoftext|>


<commit_before>// "Hello World" in C++
#include <iostream>
using namespace std;

int main ()
{
    cout << "Hello World!" <<endl;
    cout << "Hello World!" <<endl;
    cout << "Hello World!" <<endl;
    cout << "Hello World!" <<endl;
    cout << "Hello World!" <<endl;
    return 0;
}
<commit_msg>insert blank line after each row<commit_after>// "Hello World" in C++
#include <iostream>
using namespace std;

int main ()
{
    cout << "Hello World!" <<endl;
    cout <<endl;
    cout << "Hello World!" <<endl;
    cout <<endl;
    cout << "Hello World!" <<endl;
    cout <<endl;
    cout << "Hello World!" <<endl;
    cout <<endl;
    cout << "Hello World!" <<endl;
    cout <<endl;
    return 0;
}
<|endoftext|>