<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2015, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_attributes.h"
#include "condor_classad.h"
#include "condor_config.h"
#include "condor_constants.h"
#include "condor_uid.h"
#include "condor_md.h"
#include "directory_util.h"
#include "file_lock.h"
#include "filename_tools.h"
#include "stat_wrapper.h"
#include <sys/stat.h>
#include <stdlib.h>
#include <string>

#ifndef WIN32
	#include <unistd.h>
#endif

#ifdef HAVE_HTTP_PUBLIC_FILES

using namespace std;

namespace {	// Anonymous namespace to limit scope of names to this file

const int HASHNAMELEN = 17;

static string MakeHashName(const char* fileName, time_t fileModifiedTime) {

	unsigned char hashResult[HASHNAMELEN * 3]; // Allocate extra space for safety.

	// Convert the modified time to a string object
	std::string modifiedTimeStr = std::to_string((long long int) fileModifiedTime);

	// Create a new string which will be the source for our hash function.
	// This will append two strings:
	// 1. Full path to the file
	// 2. Modified time of the file
	unsigned char* hashSource = new unsigned char[strlen(fileName)
									+ strlen(modifiedTimeStr.c_str()) + 1];
	strcpy( (char*) hashSource, fileName );
	strcat( (char*) hashSource, modifiedTimeStr.c_str() );

	// Now calculate the hash
	memcpy(hashResult, Condor_MD_MAC::computeOnce(hashSource,
		strlen((const char*) hashSource)), HASHNAMELEN);
	char entryHashName[HASHNAMELEN * 2]; // 2 chars per hex byte
	entryHashName[0] = '\0';
	char letter[3];
	for (int i = 0; i < HASHNAMELEN - 1; ++i) {
		sprintf(letter, "%x", hashResult[i]);
		strcat(entryHashName, letter);
	}

	return entryHashName;
}

// WARNING!  This code changes priv state.  Be very careful if modifying it.
// Do not return in the block of code where the priv has been set to either
// condor or root.  -zmiller
static bool MakeLink(const char* srcFilePath, const string &newLink) {

	bool retVal = false;
	int srcFileInodeNum;
	int targetLinkInodeNum;
	struct stat srcFileStat;
	struct stat targetLinkStat;

	// Make sure the necessary parameters are set
	std::string webRootDir;
	param(webRootDir, "HTTP_PUBLIC_FILES_ROOT_DIR");
	if(webRootDir.empty()) {
		dprintf(D_ALWAYS, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ROOT_DIR "
						"not set! Falling back to regular file transfer\n");
		return (false);
	}
	std::string webRootOwner;
	param(webRootOwner, "HTTP_PUBLIC_FILES_ROOT_OWNER");
	if(webRootOwner.empty()) {
		dprintf(D_ALWAYS, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ROOT_OWNER "
						"not set! Falling back to regular file transfer\n");
		return (false);
	}
	char goodPath[PATH_MAX];
	if (realpath(webRootDir.c_str(), goodPath) == NULL) {
		dprintf(D_ALWAYS, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ROOT_DIR "
			"not a valid path: %s. Falling back to regular file transfer.\n",
			webRootDir.c_str());
		return (false);
	}

	// Determine the full path of the access file. Save it to a std::string and
	// deallocate the memory that dircat() returned.
	char* hardLinkFilePath = dircat(goodPath, newLink.c_str());
	std::string accessFilePath(hardLinkFilePath);
	accessFilePath += ".access";
	delete [] hardLinkFilePath;

	// STARTING HERE, DO NOT RETURN FROM THIS FUNCTION WITHOUT RESETTING
	// THE ORIGINAL PRIV STATE.

	// Check if an access file exists (which will be the case if someone has
	// already sent the source file).
	// If it does exist, lock it so that condor_preen cannot open it while
	// garbage collecting.
	// If it does not exist, carry on. We'll create it before exiting.

	priv_state original_priv = set_root_priv();
	FileLock *accessFileLock = NULL;

	if(access(accessFilePath.c_str(), F_OK) == 0) {
		accessFileLock = new FileLock(accessFilePath.c_str(), true, false);

		// Try to grab a lock on the access file. This should block until it
		// obtains the lock. If this fails for any reason, bail out.
		bool obtainedLock = accessFileLock->obtain(WRITE_LOCK);
		if(!obtainedLock) {
			dprintf(D_ALWAYS, "MakeLink: Failed to obtain lock on access file with"
				" error code %d (%s).\n", errno, strerror(errno));
			set_priv(original_priv);
			return (false);
		}
	}

	// Impersonate the user and open the file using safe_open(). This will allow
	// us to verify the user has privileges to access the file, and later to
	// verify the hard link points back to the same inode.
	set_user_priv();

	bool fileOK = false;
	FILE *srcFile = safe_fopen_wrapper(srcFilePath, "r");
	if (srcFile) {
		if(stat(srcFilePath, &srcFileStat) == 0) {
			srcFileInodeNum = srcFileStat.st_ino;
			fileOK = (srcFileStat.st_mode & S_IRUSR); // Verify readable by owner
		}
	}
	if (fileOK == false) {
		dprintf(D_ALWAYS, "MakeLink: Cannot transfer -- public input file not "
			"readable by user: %s\n", srcFilePath);
		set_priv(original_priv);
		return (false);
	}
	fclose(srcFile);

	// Create the hard link using root privileges; it will automatically get
	// owned by the same owner of the file. If the link already exists, don't do
	// anything at this point, we'll check later to make sure it points to the
	// correct inode.
	const char *const targetLinkPath = dircat(goodPath, newLink.c_str()); // needs to be freed

	// Switch to root privileges, so we can test if the link exists, and create
	// it if it does not
	set_root_priv();

	// Check if target link already exists
	FILE *targetLink = safe_fopen_wrapper(targetLinkPath, "r");
	if (targetLink) {
		// If link exists, update the .access file timestamp.
		retVal = true;
		delete [] targetLinkPath;
		fclose(targetLink);
	}
	else {
		// Link does not exist, so create it as root.
		if (link(srcFilePath, targetLinkPath) == 0) {
			// so far, so good!
			retVal = true;
		}
		else {
			dprintf(D_ALWAYS, "MakeLink: Could not link %s to %s, error: %s\n",
				targetLinkPath, srcFilePath, strerror(errno));
		}
	}

	// Now we need to make sure nothing devious has happened, that the hard link
	// points to the file we're expecting. First, make sure that the user
	// specified by HTTP_PUBLIC_FILES_ROOT_OWNER is a valid user.
	uid_t link_uid = -1;
	gid_t link_gid = -1;
	bool isValidUser = pcache()->get_user_ids(webRootOwner.c_str(), link_uid, link_gid);
	if (!isValidUser) {
		dprintf(D_ALWAYS, "Unable to look up HTTP_PUBLIC_FILES_ROOT_OWNER (%s)"
				" in /etc/passwd. Aborting.\n", webRootOwner.c_str());
		retVal = false;
	}

	if (link_uid == 0 || link_gid == 0) {
		dprintf(D_ALWAYS, "HTTP_PUBLIC_FILES_ROOT_OWNER (%s)"
			" in /etc/passwd has UID 0.  Aborting.\n", webRootOwner.c_str());
		retVal = false;
	}

	// Now that we've verified HTTP_PUBLIC_FILES_ROOT_OWNER is a valid user,
	// switch privileges to this user. Open the hard link. Verify that the
	// inode is the same as the file we opened earlier on.
	if (retVal == true) {
		if(setegid(link_gid) == -1) {
			dprintf(D_ALWAYS, "MakeLink: Error switching to group ID %d\n", link_gid);
			retVal = false;
		}
		if(seteuid(link_uid) == -1) {
			dprintf(D_ALWAYS, "MakeLink: Error switching to user ID %d\n", link_uid);
			retVal = false;
		}

		if (stat(targetLinkPath, &targetLinkStat) == 0) {
			targetLinkInodeNum = targetLinkStat.st_ino;
			if (srcFileInodeNum == targetLinkInodeNum) {
				retVal = true;
			}
			else {
				dprintf(D_ALWAYS, "Source file %s inode (%d) does not match "
					"hard link %s inode (%d), aborting.\n", srcFilePath,
					srcFileInodeNum, targetLinkPath, targetLinkInodeNum);
			}
		}
		else {
			retVal = false;
			dprintf(D_ALWAYS, "Cannot open hard link %s as user %s. Reverting to "
				"regular file transfer.\n", targetLinkPath, webRootOwner.c_str());
		}
	}

	// Touch the access file. This will create it if it doesn't exist, or update
	// the timestamp if it does.
	FILE* accessFile = fopen(accessFilePath.c_str(), "w");
	if (accessFile) {
		fclose(accessFile);
	}
	else {
		dprintf(D_ALWAYS, "Failed to update access file %s.\n", accessFilePath.c_str());
	}

	// Release the lock on the access file
	if(!accessFileLock->release()) {
		dprintf(D_ALWAYS, "MakeLink: Failed to release lock on access file with"
			" error code %d (%s).\n", errno, strerror(errno));
	}

	// Free the target link path
	delete [] targetLinkPath;

	// Reset priv state
	set_priv(original_priv);

	return retVal;
}

static string MakeAbsolutePath(const char* path, const char* initialWorkingDir) {
	if (is_relative_to_cwd(path)) {
		string fullPath = initialWorkingDir;
		fullPath += DIR_DELIM_CHAR;
		fullPath += path;
		return (fullPath);
	}
	return (path);
}

} // end namespace

void ProcessCachedInpFiles(ClassAd *const Ad, StringList *const InputFiles,
	StringList &PubInpFiles) {

	char *initialWorkingDir = NULL;
	const char *path;
	MyString remap;
	struct stat fileStat;
	time_t fileModifiedTime = time(NULL);

	if (PubInpFiles.isEmpty() == false) {
		const char *webServerAddress = param("HTTP_PUBLIC_FILES_ADDRESS");

		// If a web server address is not defined, exit quickly. The file
		// transfer will go on using the regular CEDAR protocol.
		if(!webServerAddress) {
			dprintf(D_FULLDEBUG, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ADDRESS "
							"not set! Falling back to regular file transfer\n");
			return;
		}

		// Build out the base URL for public files
		string url = "http://";
		url += webServerAddress;
		url += "/";

		PubInpFiles.rewind();

		if (Ad->LookupString(ATTR_JOB_IWD, &initialWorkingDir) != 1) {
			dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Job ad did not have an "
				"initialWorkingDir! Falling back to regular file transfer\n");
			return;
		}
		while ((path = PubInpFiles.next()) != NULL) {
			// Determine the full path of the file to be transferred
			string fullPath = MakeAbsolutePath(path, initialWorkingDir);

			// Determine the time last modified of the file to be transferred
			if( stat( fullPath.c_str(), &fileStat ) == 0 ) {
				struct timespec fileTime = fileStat.st_mtim;
				fileModifiedTime = fileTime.tv_sec;
			}
			else {
				dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Unable to access file "
					"%s. Falling back to regular file transfer\n", fullPath.c_str());
				free( initialWorkingDir );
				return;
			}

			string hashName = MakeHashName( fullPath.c_str(), fileModifiedTime );
			if (MakeLink(fullPath.c_str(), hashName)) {
				InputFiles->remove(path); // Remove plain file name from InputFiles
				remap += hashName;
				remap += "=";
				remap += basename(path);
				remap += ";";
				hashName = url + hashName;
				const char *const namePtr = hashName.c_str();
				if ( !InputFiles->contains(namePtr) ) {
					InputFiles->append(namePtr);
					dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Adding url to "
												"InputFiles: %s\n", namePtr);
				}
				else dprintf(D_FULLDEBUG, "mk_cache_links.cpp: url already "
											"in InputFiles: %s\n", namePtr);
			}
			else {
				dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Failed to generate "
									 "hash link for %s\n", fullPath.c_str());
			}
		}
		free( initialWorkingDir );
		if ( remap.Length() > 0 ) {
			MyString remapnew;
			char *buf = NULL;
			if (Ad->LookupString(ATTR_TRANSFER_INPUT_REMAPS, &buf) == 1) {
				remapnew = buf;
				free(buf);
				buf = NULL;
				remapnew += ";";
			}
			remapnew += remap;
			if (Ad->Assign(ATTR_TRANSFER_INPUT_REMAPS, remap.Value()) == false) {
				dprintf(D_ALWAYS, "mk_cache_links.cpp: Could not add to jobAd: "
													"%s\n", remap.c_str());
			}
		}
	}
	else
		dprintf(D_FULLDEBUG, "mk_cache_links.cpp: No public input files.\n");
}

#endif

<commit_msg>Removed erroneous delete[] call (#6452)<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2015, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_attributes.h"
#include "condor_classad.h"
#include "condor_config.h"
#include "condor_constants.h"
#include "condor_uid.h"
#include "condor_md.h"
#include "directory_util.h"
#include "file_lock.h"
#include "filename_tools.h"
#include "stat_wrapper.h"
#include <sys/stat.h>
#include <stdlib.h>
#include <string>

#ifndef WIN32
	#include <unistd.h>
#endif

#ifdef HAVE_HTTP_PUBLIC_FILES

using namespace std;

namespace {	// Anonymous namespace to limit scope of names to this file

const int HASHNAMELEN = 17;

static string MakeHashName(const char* fileName, time_t fileModifiedTime) {

	unsigned char hashResult[HASHNAMELEN * 3]; // Allocate extra space for safety.

	// Convert the modified time to a string object
	std::string modifiedTimeStr = std::to_string((long long int) fileModifiedTime);

	// Create a new string which will be the source for our hash function.
	// This will append two strings:
	// 1. Full path to the file
	// 2. Modified time of the file
	unsigned char* hashSource = new unsigned char[strlen(fileName)
									+ strlen(modifiedTimeStr.c_str()) + 1];
	strcpy( (char*) hashSource, fileName );
	strcat( (char*) hashSource, modifiedTimeStr.c_str() );

	// Now calculate the hash
	memcpy(hashResult, Condor_MD_MAC::computeOnce(hashSource,
		strlen((const char*) hashSource)), HASHNAMELEN);
	char entryHashName[HASHNAMELEN * 2]; // 2 chars per hex byte
	entryHashName[0] = '\0';
	char letter[3];
	for (int i = 0; i < HASHNAMELEN - 1; ++i) {
		sprintf(letter, "%x", hashResult[i]);
		strcat(entryHashName, letter);
	}

	return entryHashName;
}

// WARNING!  This code changes priv state.  Be very careful if modifying it.
// Do not return in the block of code where the priv has been set to either
// condor or root.  -zmiller
static bool MakeLink(const char* srcFilePath, const string &newLink) {

	bool retVal = false;
	int srcFileInodeNum;
	int targetLinkInodeNum;
	struct stat srcFileStat;
	struct stat targetLinkStat;

	// Make sure the necessary parameters are set
	std::string webRootDir;
	param(webRootDir, "HTTP_PUBLIC_FILES_ROOT_DIR");
	if(webRootDir.empty()) {
		dprintf(D_ALWAYS, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ROOT_DIR "
						"not set! Falling back to regular file transfer\n");
		return (false);
	}
	std::string webRootOwner;
	param(webRootOwner, "HTTP_PUBLIC_FILES_ROOT_OWNER");
	if(webRootOwner.empty()) {
		dprintf(D_ALWAYS, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ROOT_OWNER "
						"not set! Falling back to regular file transfer\n");
		return (false);
	}
	char goodPath[PATH_MAX];
	if (realpath(webRootDir.c_str(), goodPath) == NULL) {
		dprintf(D_ALWAYS, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ROOT_DIR "
			"not a valid path: %s. Falling back to regular file transfer.\n",
			webRootDir.c_str());
		return (false);
	}

	// Determine the full path of the access file. Save it to a std::string and
	// deallocate the memory that dircat() returned.
	char* hardLinkFilePath = dircat(goodPath, newLink.c_str());
	std::string accessFilePath(hardLinkFilePath);
	accessFilePath += ".access";
	delete [] hardLinkFilePath;

	// STARTING HERE, DO NOT RETURN FROM THIS FUNCTION WITHOUT RESETTING
	// THE ORIGINAL PRIV STATE.

	// Check if an access file exists (which will be the case if someone has
	// already sent the source file).
	// If it does exist, lock it so that condor_preen cannot open it while
	// garbage collecting.
	// If it does not exist, carry on. We'll create it before exiting.

	priv_state original_priv = set_root_priv();
	FileLock *accessFileLock = NULL;

	if(access(accessFilePath.c_str(), F_OK) == 0) {
		accessFileLock = new FileLock(accessFilePath.c_str(), true, false);

		// Try to grab a lock on the access file. This should block until it
		// obtains the lock. If this fails for any reason, bail out.
		bool obtainedLock = accessFileLock->obtain(WRITE_LOCK);
		if(!obtainedLock) {
			dprintf(D_ALWAYS, "MakeLink: Failed to obtain lock on access file with"
				" error code %d (%s).\n", errno, strerror(errno));
			set_priv(original_priv);
			return (false);
		}
	}

	// Impersonate the user and open the file using safe_open(). This will allow
	// us to verify the user has privileges to access the file, and later to
	// verify the hard link points back to the same inode.
	set_user_priv();

	bool fileOK = false;
	FILE *srcFile = safe_fopen_wrapper(srcFilePath, "r");
	if (srcFile) {
		if(stat(srcFilePath, &srcFileStat) == 0) {
			srcFileInodeNum = srcFileStat.st_ino;
			fileOK = (srcFileStat.st_mode & S_IRUSR); // Verify readable by owner
		}
	}
	if (fileOK == false) {
		dprintf(D_ALWAYS, "MakeLink: Cannot transfer -- public input file not "
			"readable by user: %s\n", srcFilePath);
		set_priv(original_priv);
		return (false);
	}
	fclose(srcFile);

	// Create the hard link using root privileges; it will automatically get
	// owned by the same owner of the file. If the link already exists, don't do
	// anything at this point, we'll check later to make sure it points to the
	// correct inode.
	const char *const targetLinkPath = dircat(goodPath, newLink.c_str()); // needs to be freed

	// Switch to root privileges, so we can test if the link exists, and create
	// it if it does not
	set_root_priv();

	// Check if target link already exists
	FILE *targetLink = safe_fopen_wrapper(targetLinkPath, "r");
	if (targetLink) {
		// If link exists, update the .access file timestamp.
		retVal = true;
		fclose(targetLink);
	}
	else {
		// Link does not exist, so create it as root.
		if (link(srcFilePath, targetLinkPath) == 0) {
			// so far, so good!
			retVal = true;
		}
		else {
			dprintf(D_ALWAYS, "MakeLink: Could not link %s to %s, error: %s\n",
				targetLinkPath, srcFilePath, strerror(errno));
		}
	}

	// Now we need to make sure nothing devious has happened, that the hard link
	// points to the file we're expecting. First, make sure that the user
	// specified by HTTP_PUBLIC_FILES_ROOT_OWNER is a valid user.
	uid_t link_uid = -1;
	gid_t link_gid = -1;
	bool isValidUser = pcache()->get_user_ids(webRootOwner.c_str(), link_uid, link_gid);
	if (!isValidUser) {
		dprintf(D_ALWAYS, "Unable to look up HTTP_PUBLIC_FILES_ROOT_OWNER (%s)"
				" in /etc/passwd. Aborting.\n", webRootOwner.c_str());
		retVal = false;
	}

	if (link_uid == 0 || link_gid == 0) {
		dprintf(D_ALWAYS, "HTTP_PUBLIC_FILES_ROOT_OWNER (%s)"
			" in /etc/passwd has UID 0.  Aborting.\n", webRootOwner.c_str());
		retVal = false;
	}

	// Now that we've verified HTTP_PUBLIC_FILES_ROOT_OWNER is a valid user,
	// switch privileges to this user. Open the hard link. Verify that the
	// inode is the same as the file we opened earlier on.
	if (retVal == true) {
		if(setegid(link_gid) == -1) {
			dprintf(D_ALWAYS, "MakeLink: Error switching to group ID %d\n", link_gid);
			retVal = false;
		}
		if(seteuid(link_uid) == -1) {
			dprintf(D_ALWAYS, "MakeLink: Error switching to user ID %d\n", link_uid);
			retVal = false;
		}

		if (stat(targetLinkPath, &targetLinkStat) == 0) {
			targetLinkInodeNum = targetLinkStat.st_ino;
			if (srcFileInodeNum == targetLinkInodeNum) {
				retVal = true;
			}
			else {
				dprintf(D_ALWAYS, "Source file %s inode (%d) does not match "
					"hard link %s inode (%d), aborting.\n", srcFilePath,
					srcFileInodeNum, targetLinkPath, targetLinkInodeNum);
			}
		}
		else {
			retVal = false;
			dprintf(D_ALWAYS, "Cannot open hard link %s as user %s. Reverting to "
				"regular file transfer.\n", targetLinkPath, webRootOwner.c_str());
		}
	}

	// Touch the access file. This will create it if it doesn't exist, or update
	// the timestamp if it does.
	FILE* accessFile = fopen(accessFilePath.c_str(), "w");
	if (accessFile) {
		fclose(accessFile);
	}
	else {
		dprintf(D_ALWAYS, "Failed to update access file %s.\n", accessFilePath.c_str());
	}

	// Release the lock on the access file
	if(!accessFileLock->release()) {
		dprintf(D_ALWAYS, "MakeLink: Failed to release lock on access file with"
			" error code %d (%s).\n", errno, strerror(errno));
	}

	// Free the target link path
	delete [] targetLinkPath;

	// Reset priv state
	set_priv(original_priv);

	return retVal;
}

static string MakeAbsolutePath(const char* path, const char* initialWorkingDir) {
	if (is_relative_to_cwd(path)) {
		string fullPath = initialWorkingDir;
		fullPath += DIR_DELIM_CHAR;
		fullPath += path;
		return (fullPath);
	}
	return (path);
}

} // end namespace

void ProcessCachedInpFiles(ClassAd *const Ad, StringList *const InputFiles,
	StringList &PubInpFiles) {

	char *initialWorkingDir = NULL;
	const char *path;
	MyString remap;
	struct stat fileStat;
	time_t fileModifiedTime = time(NULL);

	if (PubInpFiles.isEmpty() == false) {
		const char *webServerAddress = param("HTTP_PUBLIC_FILES_ADDRESS");

		// If a web server address is not defined, exit quickly. The file
		// transfer will go on using the regular CEDAR protocol.
		if(!webServerAddress) {
			dprintf(D_FULLDEBUG, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ADDRESS "
							"not set! Falling back to regular file transfer\n");
			return;
		}

		// Build out the base URL for public files
		string url = "http://";
		url += webServerAddress;
		url += "/";

		PubInpFiles.rewind();

		if (Ad->LookupString(ATTR_JOB_IWD, &initialWorkingDir) != 1) {
			dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Job ad did not have an "
				"initialWorkingDir! Falling back to regular file transfer\n");
			return;
		}
		while ((path = PubInpFiles.next()) != NULL) {
			// Determine the full path of the file to be transferred
			string fullPath = MakeAbsolutePath(path, initialWorkingDir);

			// Determine the time last modified of the file to be transferred
			if( stat( fullPath.c_str(), &fileStat ) == 0 ) {
				struct timespec fileTime = fileStat.st_mtim;
				fileModifiedTime = fileTime.tv_sec;
			}
			else {
				dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Unable to access file "
					"%s. Falling back to regular file transfer\n", fullPath.c_str());
				free( initialWorkingDir );
				return;
			}

			string hashName = MakeHashName( fullPath.c_str(), fileModifiedTime );
			if (MakeLink(fullPath.c_str(), hashName)) {
				InputFiles->remove(path); // Remove plain file name from InputFiles
				remap += hashName;
				remap += "=";
				remap += basename(path);
				remap += ";";
				hashName = url + hashName;
				const char *const namePtr = hashName.c_str();
				if ( !InputFiles->contains(namePtr) ) {
					InputFiles->append(namePtr);
					dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Adding url to "
												"InputFiles: %s\n", namePtr);
				}
				else dprintf(D_FULLDEBUG, "mk_cache_links.cpp: url already "
											"in InputFiles: %s\n", namePtr);
			}
			else {
				dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Failed to generate "
									 "hash link for %s\n", fullPath.c_str());
			}
		}
		free( initialWorkingDir );
		if ( remap.Length() > 0 ) {
			MyString remapnew;
			char *buf = NULL;
			if (Ad->LookupString(ATTR_TRANSFER_INPUT_REMAPS, &buf) == 1) {
				remapnew = buf;
				free(buf);
				buf = NULL;
				remapnew += ";";
			}
			remapnew += remap;
			if (Ad->Assign(ATTR_TRANSFER_INPUT_REMAPS, remap.Value()) == false) {
				dprintf(D_ALWAYS, "mk_cache_links.cpp: Could not add to jobAd: "
													"%s\n", remap.c_str());
			}
		}
	}
	else
		dprintf(D_FULLDEBUG, "mk_cache_links.cpp: No public input files.\n");
}

#endif

<|endoftext|>


<commit_before>#include "Config.hpp"
#include "EventWatcher.hpp"
#include "IOLockWrapper.hpp"

namespace org_pqrs_KeyRemap4MacBook {
  bool* EventWatcher::item_[MAXNUM];
  IOLock* EventWatcher::lock_;

  void
  EventWatcher::initialize(void)
  {
    lock_ = IOLockWrapper::alloc();
    reset();
  }

  void
  EventWatcher::terminate(void)
  {
    IOLockWrapper::free(lock_);
  }

  void
  EventWatcher::reset(void)
  {
    IOLockWrapper::ScopedLock lk(lock_);

    for (int i = 0; i < MAXNUM; ++i) {
      item_[i] = NULL;
    }
  }

  void
  EventWatcher::on(void)
  {
    IOLockWrapper::ScopedLock lk(lock_);

    if (config.debug_devel) {
      IOLog("KeyRemap4MacBook -Info- EventWatcher::on\n");
    }

    for (int i = 0; i < MAXNUM; ++i) {
      if (item_[i]) {
        *(item_[i]) = true;
        item_[i] = NULL;
      }
    }
  }

  void
  EventWatcher::set(bool& b)
  {
    IOLockWrapper::ScopedLock lk(lock_);

    b = false;
    for (int i = 0; i < MAXNUM; ++i) {
      if (item_[i] == NULL) {
        item_[i] = &b;

        if (i == MAXNUM - 1) {
          IOLog("KeyRemap4MacBook --Warning-- EventWatcher was filled up. Expand MAXNUM.\n");
        }
        return;
      }
    }
  }

  void
  EventWatcher::unset(bool& b)
  {
    IOLockWrapper::ScopedLock lk(lock_);

    for (int i = 0; i < MAXNUM; ++i) {
      if (item_[i] == &b) {
        item_[i] = NULL;
      }
    }
  }
}
<commit_msg>update EventWatcher to use IOLOG_*<commit_after>#include "Config.hpp"
#include "EventWatcher.hpp"
#include "IOLockWrapper.hpp"

namespace org_pqrs_KeyRemap4MacBook {
  bool* EventWatcher::item_[MAXNUM];
  IOLock* EventWatcher::lock_;

  void
  EventWatcher::initialize(void)
  {
    lock_ = IOLockWrapper::alloc();
    reset();
  }

  void
  EventWatcher::terminate(void)
  {
    IOLockWrapper::free(lock_);
  }

  void
  EventWatcher::reset(void)
  {
    IOLockWrapper::ScopedLock lk(lock_);

    for (int i = 0; i < MAXNUM; ++i) {
      item_[i] = NULL;
    }
  }

  void
  EventWatcher::on(void)
  {
    IOLockWrapper::ScopedLock lk(lock_);

    IOLOG_DEVEL("EventWatcher::on\n");

    for (int i = 0; i < MAXNUM; ++i) {
      if (item_[i]) {
        *(item_[i]) = true;
        item_[i] = NULL;
      }
    }
  }

  void
  EventWatcher::set(bool& b)
  {
    IOLockWrapper::ScopedLock lk(lock_);

    b = false;
    for (int i = 0; i < MAXNUM; ++i) {
      if (item_[i] == NULL) {
        item_[i] = &b;

        if (i == MAXNUM - 1) {
          IOLOG_WARN("EventWatcher was filled up. Expand MAXNUM.\n");
        }
        return;
      }
    }
  }

  void
  EventWatcher::unset(bool& b)
  {
    IOLockWrapper::ScopedLock lk(lock_);

    for (int i = 0; i < MAXNUM; ++i) {
      if (item_[i] == &b) {
        item_[i] = NULL;
      }
    }
  }
}
<|endoftext|>


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

/**
 * @file ocpoc_adc.cpp
 *
 * OcPoC ADC Driver
 *
 * @author Lianying Ji <ji@aerotenna.com>
 * @author Dave Royer <dave@aerotenna.com>
 */

#include <px4_config.h>
#include <px4_tasks.h>
#include <px4_posix.h>
#include <px4_adc.h>
#include <drivers/drv_adc.h>

#include <VirtDevObj.hpp>

#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <string.h>

#define ADC_BASE_DEV_PATH "/dev/adc"
#define ADC_VOLTAGE_PATH "/sys/bus/iio/devices/iio:device0/in_voltage8_raw"

__BEGIN_DECLS
__EXPORT int ocpoc_adc_main(int argc, char *argv[]);
__END_DECLS

class OcpocADC: public DriverFramework::VirtDevObj
{
public:
	OcpocADC();
	virtual ~OcpocADC();

	virtual int init();

	virtual ssize_t devRead(void *buf, size_t count) override;
	virtual int devIOCTL(unsigned long request, unsigned long arg) override;

protected:
	virtual void _measure() override;

private:
	int read(struct adc_msg_s(*buf)[12], unsigned int len);

	pthread_mutex_t _samples_lock;
	adc_msg_s _samples;
	FILE *xadc_fd;
};

OcpocADC::OcpocADC()
	: DriverFramework::VirtDevObj("ocpoc_adc", ADC0_DEVICE_PATH, ADC_BASE_DEV_PATH, 1e6 / 100)
{
	pthread_mutex_init(&_samples_lock, NULL);
}

OcpocADC::~OcpocADC()
{
	pthread_mutex_destroy(&_samples_lock);
}

void OcpocADC::_measure()
{
	struct adc_msg_s tmp_samples[12];

	int ret = read(&tmp_samples, sizeof(tmp_samples));

	if (ret != 0) {
		PX4_ERR("ocpoc_adc_read: %d", ret);
	}

	pthread_mutex_lock(&_samples_lock);
	memcpy(&_samples, &tmp_samples, sizeof(tmp_samples));
	pthread_mutex_unlock(&_samples_lock);
}

int OcpocADC::init()
{
	int ret;

	ret = DriverFramework::VirtDevObj::init();

	if (ret != PX4_OK) {
		PX4_ERR("init failed");
		return ret;
	}

	return PX4_OK;
}

int OcpocADC::devIOCTL(unsigned long request, unsigned long arg)
{
	return -ENOTTY;
}

ssize_t OcpocADC::devRead(void *buf, size_t count)
{
	const size_t maxsize = sizeof(_samples);
	int ret;

	if (count > maxsize) {
		count = maxsize;
	}

	ret = pthread_mutex_trylock(&_samples_lock);

	if (ret != 0) {
		return 0;
	}

	memcpy(buf, &_samples, count);
	pthread_mutex_unlock(&_samples_lock);

	return count;
}

int OcpocADC::read(struct adc_msg_s(*buf)[12], unsigned int len)
{
	uint32_t buff[1];
	int ret = 0;

	xadc_fd = fopen(ADC_VOLTAGE_PATH, "r");

	if (xadc_fd != NULL) {
		fscanf(xadc_fd, "%d", buff);
		fclose(xadc_fd);

		(*buf)[0].am_data = buff[0];

	} else {
		(*buf)[0].am_data = 0;
		ret = -1;
	}

	(*buf)[0].am_channel = ADC_BATTERY_VOLTAGE_CHANNEL;

	return ret;
}

static OcpocADC *instance = nullptr;

int ocpoc_adc_main(int argc, char *argv[])
{
	int ret;

	if (argc < 2) {
		PX4_WARN("usage: {start|stop|test}");
		return PX4_ERROR;
	}

	if (!strcmp(argv[1], "start")) {
		if (instance) {
			PX4_WARN("already started");
			return PX4_OK;
		}

		instance = new OcpocADC;

		if (!instance) {
			PX4_WARN("not enough memory");
			return PX4_ERROR;
		}

		if (instance->init() != PX4_OK) {
			delete instance;
			instance = nullptr;
			PX4_WARN("init failed");
			return PX4_ERROR;
		}

		return PX4_OK;

	} else if (!strcmp(argv[1], "stop")) {
		if (!instance) {
			PX4_WARN("already stopped");
			return PX4_OK;
		}

		delete instance;
		instance = nullptr;
		return PX4_OK;

	} else if (!strcmp(argv[1], "test")) {
		if (!instance) {
			PX4_ERR("start first");
			return PX4_ERROR;
		}

		struct adc_msg_s adc_msgs[12];

		ret = instance->devRead((char *)&adc_msgs, sizeof(adc_msgs));

		if (ret < 0) {
			PX4_ERR("ret: %s (%d)\n", strerror(ret), ret);
			return ret;

		} else {
			PX4_INFO("ADC Data: %d", adc_msgs[0].am_data);
		}

		return PX4_OK;

	} else {
		PX4_WARN("action (%s) not supported", argv[1]);

		return PX4_ERROR;
	}

	return PX4_OK;

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

/**
 * @file ocpoc_adc.cpp
 *
 * OcPoC ADC Driver
 *
 * @author Lianying Ji <ji@aerotenna.com>
 * @author Dave Royer <dave@aerotenna.com>
 */

#include <px4_config.h>
#include <px4_tasks.h>
#include <px4_posix.h>
#include <px4_adc.h>
#include <drivers/drv_adc.h>

#include <VirtDevObj.hpp>

#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <string.h>

#define ADC_BASE_DEV_PATH "/dev/adc"
#define ADC_VOLTAGE_PATH "/sys/bus/iio/devices/iio:device0/in_voltage8_raw"

__BEGIN_DECLS
__EXPORT int ocpoc_adc_main(int argc, char *argv[]);
__END_DECLS

class OcpocADC: public DriverFramework::VirtDevObj
{
public:
	OcpocADC();
	virtual ~OcpocADC();

	virtual int init();

	virtual ssize_t devRead(void *buf, size_t count) override;
	virtual int devIOCTL(unsigned long request, unsigned long arg) override;

protected:
	virtual void _measure() override;

private:
	int read(struct adc_msg_s(*buf)[12], unsigned int len);

	pthread_mutex_t _samples_lock;
	adc_msg_s _samples;
};

OcpocADC::OcpocADC()
	: DriverFramework::VirtDevObj("ocpoc_adc", ADC0_DEVICE_PATH, ADC_BASE_DEV_PATH, 1e6 / 100)
{
	pthread_mutex_init(&_samples_lock, NULL);
}

OcpocADC::~OcpocADC()
{
	pthread_mutex_destroy(&_samples_lock);
}

void OcpocADC::_measure()
{
	struct adc_msg_s tmp_samples[12];

	int ret = read(&tmp_samples, sizeof(tmp_samples));

	if (ret != 0) {
		PX4_ERR("ocpoc_adc_read: %d", ret);
	}

	pthread_mutex_lock(&_samples_lock);
	memcpy(&_samples, &tmp_samples, sizeof(tmp_samples));
	pthread_mutex_unlock(&_samples_lock);
}

int OcpocADC::init()
{
	int ret;

	ret = DriverFramework::VirtDevObj::init();

	if (ret != PX4_OK) {
		PX4_ERR("init failed");
		return ret;
	}

	return PX4_OK;
}

int OcpocADC::devIOCTL(unsigned long request, unsigned long arg)
{
	return -ENOTTY;
}

ssize_t OcpocADC::devRead(void *buf, size_t count)
{
	const size_t maxsize = sizeof(_samples);
	int ret;

	if (count > maxsize) {
		count = maxsize;
	}

	ret = pthread_mutex_trylock(&_samples_lock);

	if (ret != 0) {
		return 0;
	}

	memcpy(buf, &_samples, count);
	pthread_mutex_unlock(&_samples_lock);

	return count;
}

int OcpocADC::read(struct adc_msg_s(*buf)[12], unsigned int len)
{
	uint32_t buff[1];
	int ret = 0;

	FILE *xadc_fd = fopen(ADC_VOLTAGE_PATH, "r");

	if (xadc_fd != NULL) {
		fscanf(xadc_fd, "%d", buff);
		fclose(xadc_fd);

		(*buf)[0].am_data = buff[0];

	} else {
		(*buf)[0].am_data = 0;
		ret = -1;
	}

	(*buf)[0].am_channel = ADC_BATTERY_VOLTAGE_CHANNEL;

	return ret;
}

static OcpocADC *instance = nullptr;

int ocpoc_adc_main(int argc, char *argv[])
{
	int ret;

	if (argc < 2) {
		PX4_WARN("usage: {start|stop|test}");
		return PX4_ERROR;
	}

	if (!strcmp(argv[1], "start")) {
		if (instance) {
			PX4_WARN("already started");
			return PX4_OK;
		}

		instance = new OcpocADC;

		if (!instance) {
			PX4_WARN("not enough memory");
			return PX4_ERROR;
		}

		if (instance->init() != PX4_OK) {
			delete instance;
			instance = nullptr;
			PX4_WARN("init failed");
			return PX4_ERROR;
		}

		return PX4_OK;

	} else if (!strcmp(argv[1], "stop")) {
		if (!instance) {
			PX4_WARN("already stopped");
			return PX4_OK;
		}

		delete instance;
		instance = nullptr;
		return PX4_OK;

	} else if (!strcmp(argv[1], "test")) {
		if (!instance) {
			PX4_ERR("start first");
			return PX4_ERROR;
		}

		struct adc_msg_s adc_msgs[12];

		ret = instance->devRead((char *)&adc_msgs, sizeof(adc_msgs));

		if (ret < 0) {
			PX4_ERR("ret: %s (%d)\n", strerror(ret), ret);
			return ret;

		} else {
			PX4_INFO("ADC Data: %d", adc_msgs[0].am_data);
		}

		return PX4_OK;

	} else {
		PX4_WARN("action (%s) not supported", argv[1]);

		return PX4_ERROR;
	}

	return PX4_OK;

}
<|endoftext|>


<commit_before>
#include "engine/world/item/Inventory.h"

namespace engine {
namespace world {
namespace item {

	// initialize an inventory with a pointer that tells us
	// who the inventory belongs too so we can perform
	// actions on the player
	void Inventory::init( player::Player * owner )
	{
		_playerOwner = owner;
	}

	// Deletes the item from existance completely, not accessible
	// anywhere, because of the delete
	bool Inventory::destroyItem(String name) {
		BaseItem * item = _inventoryMap[name];
		bool destroyed = false;
		if ( item )
		{
			item->onDestroy(_playerOwner);
			_inventoryMap.erase(name);
			delete item;
			destroyed = true;
		}
		return destroyed;
	}

	// Removes the item from the player map and returns
	// and instance of the object
	BaseItem * Inventory::dropItem(String name) {
		BaseItem * item = _inventoryMap[name];
		if ( item )
		{
			item->onDrop(_playerOwner);
			_inventoryMap.erase(name);
		}
		return item;
	}

	// You can use items! Define the effect in the individual items.
	bool Inventory::useItem(String name) {
		BaseItem * item = _inventoryMap[name];
		bool used = false;
		if ( item && item->getQuantity() > 0 )
		{
			item->onUse(_playerOwner);
			used = true;
		}
		return used;
	}

	// TODO Add some weight checking, or max inventory count or something later.
	bool Inventory::insertItem(BaseItem * item) {
		bool inserted = false;
		if ( item ) {
			BaseItem * myItem = _inventoryMap[item->getName()]; // Checking if an entry exists
			if ( myItem ) {
				myItem->setQuantity( myItem->getQuantity() + item->getQuantity() );
			}
			else {
				_inventoryMap[item->getName()] = item;
			}
			item->onPickup(_playerOwner);
			inserted = true;
		}
		return inserted;

	}

	// I imagine this one will be used in a window or something, lets discuss how to handle this
	bool Inventory::inspectItem(String name) {
		BaseItem * item = _inventoryMap[name];
		bool inspected = false;
		if ( item )
		{
			item->onInspect(_playerOwner);
			inspected = true;
		}
		return inspected;
	}

}
}
}<commit_msg>Fixed Whitespace<commit_after>
#include "engine/world/item/Inventory.h"

namespace engine {
namespace world {
namespace item {

	// initialize an inventory with a pointer that tells us
	// who the inventory belongs too so we can perform
	// actions on the player
	void Inventory::init( player::Player * owner )
	{
		_playerOwner = owner;
	}

	// Deletes the item from existance completely, not accessible
	// anywhere, because of the delete
	bool Inventory::destroyItem(String name) {
		BaseItem * item = _inventoryMap[name];
		bool destroyed = false;
		if ( item )
		{
			item->onDestroy(_playerOwner);
			_inventoryMap.erase(name);
			delete item;
			destroyed = true;
		}
		return destroyed;
	}

	// Removes the item from the player map and returns
	// and instance of the object
	BaseItem * Inventory::dropItem(String name) {
		BaseItem * item = _inventoryMap[name];
		if ( item )
		{
			item->onDrop(_playerOwner);
			_inventoryMap.erase(name);
		}
		return item;
	}

	// You can use items! Define the effect in the individual items.
	bool Inventory::useItem(String name) {
		BaseItem * item = _inventoryMap[name];
		bool used = false;
		if ( item && item->getQuantity() > 0 )
		{
			item->onUse(_playerOwner);
			used = true;
		}
		return used;
	}

	// TODO Add some weight checking, or max inventory count or something later.
	bool Inventory::insertItem(BaseItem * item) {
		bool inserted = false;
		if ( item ) {
			BaseItem * myItem = _inventoryMap[item->getName()]; // Checking if an entry exists
			if ( myItem ) {
				myItem->setQuantity( myItem->getQuantity() + item->getQuantity() );
			}
			else {
				_inventoryMap[item->getName()] = item;
			}
			item->onPickup(_playerOwner);
			inserted = true;
		}
		return inserted;

	}

	// I imagine this one will be used in a window or something, lets discuss how to handle this
	bool Inventory::inspectItem(String name) {
		BaseItem * item = _inventoryMap[name];
		bool inspected = false;
		if ( item )
		{
			item->onInspect(_playerOwner);
			inspected = true;
		}
		return inspected;
	}

}
}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Huang-Ming Huang,  Object Computing, Inc.
// All rights reserved.
//
// This file is part of mFAST.
// See the file license.txt for licensing information.
#include <iostream>
#include <string>

#include "hpp_gen.h"
#include "inl_gen.h"
#include "cpp_gen.h"
#include "mfast/coder/common/dictionary_builder.h"
#include "mfast/coder/common/template_repo.h"

// #include <boost/filesystem.hpp>
#include <stdlib.h>
#include <fstream>
#include <iterator>

// using namespace boost::filesystem;

bool check_long_option(const std::string &command, int argc, const char **argv, int &i, const char *name, const char *&output, bool &bad) {
  const auto len = std::strlen(name);
  if (std::strncmp(argv[i], name, len) != 0) {
    return false;
  } else if (argv[i][len] == '=') {
    output = &argv[i][len + 1];
    return true;
  } else if (argv[i][len] == '\0') {
    if (++i < argc) {
      output = argv[i];
    } else {
      std::cerr << command << ": option requires and argument -- " << name << std::endl;
      bad = true;
    }
    return true;
  } else {
    return false;
  }
}

bool check_short_option(const std::string &command, int argc, const char **argv, int &i, const char *&arg, char flag, const char *&output, bool &bad)
{
  if (*arg == flag) {
    if (*++arg != '\0') {
      output = arg;
      arg += std::strlen(arg);
    } else if (++i < argc) {
      arg = output = argv[i];
      arg += std::strlen(arg);
    }
    else {
      std::cerr << command << ": option requires and argument -- " << flag << std::endl;
      bad = true;
    }
    return true;
  } else {
    return false;
  }
}

int main(int argc, const char **argv) {
  mfast::template_registry registry;

  try {
    int i = 1;

    std::string command_name = "fast_type_gen";

    const char *export_symbol = nullptr;
    const char *outer_namespace = nullptr;
    const char *header_extension = ".h";
    const char *inline_extension = ".inl";
    const char *source_extension = ".cpp";

    bool show_usage = false;
    bool bad_arguments = false;

    while ((i < argc) && (std::strlen(argv[i]) > 1) && (argv[i][0] == '-') && (std::strcmp(argv[i], "--") != 0) && !bad_arguments) {
      const char *flag = &argv[i][1];
      if (*flag == '-') {
        ++flag;
        if (std::strcmp(flag, "help") == 0) {
          show_usage = true;
        } else if (check_long_option(command_name, argc, argv, i, "--export-symbol", export_symbol, bad_arguments)) {
        } else if (check_long_option(command_name, argc, argv, i, "--namespace", outer_namespace, bad_arguments)) {
        } else if (check_long_option(command_name, argc, argv, i, "--header-extension", header_extension, bad_arguments)) {
        } else if (check_long_option(command_name, argc, argv, i, "--inline-extension", inline_extension, bad_arguments)) {
        } else if (check_long_option(command_name, argc, argv, i, "--source-extension", source_extension, bad_arguments)) {
        } else {
          std::cerr << command_name << ": illegal option -- " << flag << std::endl;
          bad_arguments = true;
        }
      } else {
        while ((i < argc) && *flag && !bad_arguments) {
          if (*flag == 'h') {
            show_usage = true;
            ++flag;
          } else if (check_short_option(command_name, argc, argv, i, flag, 'E', export_symbol, bad_arguments)) {
          } else if (check_short_option(command_name, argc, argv, i, flag, 'n', outer_namespace, bad_arguments)) {
          } else if (check_short_option(command_name, argc, argv, i, flag, 'H', header_extension, bad_arguments)) {
          } else if (check_short_option(command_name, argc, argv, i, flag, 'I', inline_extension, bad_arguments)) {
          } else if (check_short_option(command_name, argc, argv, i, flag, 'C', source_extension, bad_arguments)) {
          } else {
            std::cerr << command_name << ": illegal option -- " << *flag << std::endl;
            bad_arguments = true;
          }
        }
      }
      ++i;
    }
    if ((i < argc) && (std::strcmp(argv[i], "--") == 0))
      ++i;
    if (show_usage || bad_arguments || (i >= argc)) {
      std::ostream &output = show_usage ? std::cout : std::cerr;
      output << "usage: " << command_name << " [-E symbol] [-H extension] [-I extension] [-C extension] file ...\n"
                "       generate C++ bindings for FAST types\n";
      if (show_usage) {
        output << "\n"
                  "Options and arguments:\n"
                  "  -h, --help                  show usage and exit\n"
                  "  -E, --export-symbol=SYM     qualifier for generated types\n"
                  "  -n, --namespace=NS          namespace for generated code\n"
                  "  -C, --source-extension=EXT  source filename extension (default .cpp)\n"
                  "  -H, --header-extension=EXT  header filename extension (default .h)\n"
                  "  -I, --inline-extension=EXT  inline function filename extension (default .inl)\n"
                  "  file ...                    XML FAST message template inputs\n";
      }
      return (bad_arguments || (!show_usage && (i >= argc))) ? -1 : 0;
    }

    std::vector<mfast::dynamic_templates_description> descriptions;

    std::vector<std::string> filebases;

    mfast::simple_template_repo_t repo;

    for (int j = 0; i < argc; ++i, ++j) {

      std::ifstream ifs(argv[i]);

      if (!ifs) {
        std::cerr << command_name << ": " << argv[i] << " load failed" << std::endl;
        return -1;
      }

      std::string xml((std::istreambuf_iterator<char>(ifs)),
                      std::istreambuf_iterator<char>());

      //path f(path(argv[i]).stem());

#ifdef _WINDOWS
      char filebase_buf[_MAX_FNAME];
      _splitpath(argv[i], NULL, NULL, filebase_buf, NULL);
      boost::string_ref filebase = static_cast<const char*>(filebase_buf);
#else
      boost::string_ref filebase(argv[i]);
      filebase = filebase.substr(filebase.find_last_of('/') + 1);
      filebase = filebase.substr(0, filebase.find_last_of('.'));
#endif
      filebases.push_back(codegen_base::cpp_name(filebase));

      descriptions.emplace_back(xml.c_str(), filebases[j].c_str(), &registry);
    }

    repo.build(descriptions.begin(), descriptions.end());

    for (std::size_t j = 0; j < filebases.size(); ++j) {
      mfast::dynamic_templates_description &desc = descriptions[j];
      const std::string &filebase = filebases[j];

      hpp_gen header_gen(filebase.c_str(), header_extension);
      if (outer_namespace)
        header_gen.set_outer_ns(outer_namespace);
      if (export_symbol)
        header_gen.set_export_symbol(export_symbol);
      header_gen.set_inl_fileext(inline_extension);
      header_gen.generate(desc);

      inl_gen inline_gen(filebase.c_str(), inline_extension);
      if (outer_namespace)
        inline_gen.set_outer_ns(outer_namespace);
      inline_gen.generate(desc);

      cpp_gen source_gen(filebase.c_str(), source_extension);
      if (outer_namespace)
        source_gen.set_outer_ns(outer_namespace);
      source_gen.set_hpp_fileext(header_extension);
      source_gen.generate(desc);
    }
  } catch (boost::exception &e) {
    std::cerr << diagnostic_information(e);
    return -1;
  } catch (std::exception &e) {
    std::cerr << e.what() << "\n";
    return -1;
  }

  return 0;
}
<commit_msg>Remove commented-out code.<commit_after>// Copyright (c) 2016, Huang-Ming Huang,  Object Computing, Inc.
// All rights reserved.
//
// This file is part of mFAST.
// See the file license.txt for licensing information.
#include <iostream>
#include <string>

#include "hpp_gen.h"
#include "inl_gen.h"
#include "cpp_gen.h"
#include "mfast/coder/common/dictionary_builder.h"
#include "mfast/coder/common/template_repo.h"

#include <stdlib.h>
#include <fstream>
#include <iterator>

bool check_long_option(const std::string &command, int argc, const char **argv, int &i, const char *name, const char *&output, bool &bad) {
  const auto len = std::strlen(name);
  if (std::strncmp(argv[i], name, len) != 0) {
    return false;
  } else if (argv[i][len] == '=') {
    output = &argv[i][len + 1];
    return true;
  } else if (argv[i][len] == '\0') {
    if (++i < argc) {
      output = argv[i];
    } else {
      std::cerr << command << ": option requires and argument -- " << name << std::endl;
      bad = true;
    }
    return true;
  } else {
    return false;
  }
}

bool check_short_option(const std::string &command, int argc, const char **argv, int &i, const char *&arg, char flag, const char *&output, bool &bad)
{
  if (*arg == flag) {
    if (*++arg != '\0') {
      output = arg;
      arg += std::strlen(arg);
    } else if (++i < argc) {
      arg = output = argv[i];
      arg += std::strlen(arg);
    }
    else {
      std::cerr << command << ": option requires and argument -- " << flag << std::endl;
      bad = true;
    }
    return true;
  } else {
    return false;
  }
}

int main(int argc, const char **argv) {
  mfast::template_registry registry;

  try {
    int i = 1;

    std::string command_name = "fast_type_gen";

    const char *export_symbol = nullptr;
    const char *outer_namespace = nullptr;
    const char *header_extension = ".h";
    const char *inline_extension = ".inl";
    const char *source_extension = ".cpp";

    bool show_usage = false;
    bool bad_arguments = false;

    while ((i < argc) && (std::strlen(argv[i]) > 1) && (argv[i][0] == '-') && (std::strcmp(argv[i], "--") != 0) && !bad_arguments) {
      const char *flag = &argv[i][1];
      if (*flag == '-') {
        ++flag;
        if (std::strcmp(flag, "help") == 0) {
          show_usage = true;
        } else if (check_long_option(command_name, argc, argv, i, "--export-symbol", export_symbol, bad_arguments)) {
        } else if (check_long_option(command_name, argc, argv, i, "--namespace", outer_namespace, bad_arguments)) {
        } else if (check_long_option(command_name, argc, argv, i, "--header-extension", header_extension, bad_arguments)) {
        } else if (check_long_option(command_name, argc, argv, i, "--inline-extension", inline_extension, bad_arguments)) {
        } else if (check_long_option(command_name, argc, argv, i, "--source-extension", source_extension, bad_arguments)) {
        } else {
          std::cerr << command_name << ": illegal option -- " << flag << std::endl;
          bad_arguments = true;
        }
      } else {
        while ((i < argc) && *flag && !bad_arguments) {
          if (*flag == 'h') {
            show_usage = true;
            ++flag;
          } else if (check_short_option(command_name, argc, argv, i, flag, 'E', export_symbol, bad_arguments)) {
          } else if (check_short_option(command_name, argc, argv, i, flag, 'n', outer_namespace, bad_arguments)) {
          } else if (check_short_option(command_name, argc, argv, i, flag, 'H', header_extension, bad_arguments)) {
          } else if (check_short_option(command_name, argc, argv, i, flag, 'I', inline_extension, bad_arguments)) {
          } else if (check_short_option(command_name, argc, argv, i, flag, 'C', source_extension, bad_arguments)) {
          } else {
            std::cerr << command_name << ": illegal option -- " << *flag << std::endl;
            bad_arguments = true;
          }
        }
      }
      ++i;
    }
    if ((i < argc) && (std::strcmp(argv[i], "--") == 0))
      ++i;
    if (show_usage || bad_arguments || (i >= argc)) {
      std::ostream &output = show_usage ? std::cout : std::cerr;
      output << "usage: " << command_name << " [-E symbol] [-H extension] [-I extension] [-C extension] file ...\n"
                "       generate C++ bindings for FAST types\n";
      if (show_usage) {
        output << "\n"
                  "Options and arguments:\n"
                  "  -h, --help                  show usage and exit\n"
                  "  -E, --export-symbol=SYM     qualifier for generated types\n"
                  "  -n, --namespace=NS          namespace for generated code\n"
                  "  -C, --source-extension=EXT  source filename extension (default .cpp)\n"
                  "  -H, --header-extension=EXT  header filename extension (default .h)\n"
                  "  -I, --inline-extension=EXT  inline function filename extension (default .inl)\n"
                  "  file ...                    XML FAST message template inputs\n";
      }
      return (bad_arguments || (!show_usage && (i >= argc))) ? -1 : 0;
    }

    std::vector<mfast::dynamic_templates_description> descriptions;

    std::vector<std::string> filebases;

    mfast::simple_template_repo_t repo;

    for (int j = 0; i < argc; ++i, ++j) {

      std::ifstream ifs(argv[i]);

      if (!ifs) {
        std::cerr << command_name << ": " << argv[i] << " load failed" << std::endl;
        return -1;
      }

      std::string xml((std::istreambuf_iterator<char>(ifs)),
                      std::istreambuf_iterator<char>());

      //path f(path(argv[i]).stem());

#ifdef _WINDOWS
      char filebase_buf[_MAX_FNAME];
      _splitpath(argv[i], NULL, NULL, filebase_buf, NULL);
      boost::string_ref filebase = static_cast<const char*>(filebase_buf);
#else
      boost::string_ref filebase(argv[i]);
      filebase = filebase.substr(filebase.find_last_of('/') + 1);
      filebase = filebase.substr(0, filebase.find_last_of('.'));
#endif
      filebases.push_back(codegen_base::cpp_name(filebase));

      descriptions.emplace_back(xml.c_str(), filebases[j].c_str(), &registry);
    }

    repo.build(descriptions.begin(), descriptions.end());

    for (std::size_t j = 0; j < filebases.size(); ++j) {
      mfast::dynamic_templates_description &desc = descriptions[j];
      const std::string &filebase = filebases[j];

      hpp_gen header_gen(filebase.c_str(), header_extension);
      if (outer_namespace)
        header_gen.set_outer_ns(outer_namespace);
      if (export_symbol)
        header_gen.set_export_symbol(export_symbol);
      header_gen.set_inl_fileext(inline_extension);
      header_gen.generate(desc);

      inl_gen inline_gen(filebase.c_str(), inline_extension);
      if (outer_namespace)
        inline_gen.set_outer_ns(outer_namespace);
      inline_gen.generate(desc);

      cpp_gen source_gen(filebase.c_str(), source_extension);
      if (outer_namespace)
        source_gen.set_outer_ns(outer_namespace);
      source_gen.set_hpp_fileext(header_extension);
      source_gen.generate(desc);
    }
  } catch (boost::exception &e) {
    std::cerr << diagnostic_information(e);
    return -1;
  } catch (std::exception &e) {
    std::cerr << e.what() << "\n";
    return -1;
  }

  return 0;
}
<|endoftext|>


<commit_before>/*****************************************************************************************
 *                                                                                *
 * GHOUL                                                                                *
 * General Helpful Open Utility Library                                                  *
 *                                                                                *
 * Copyright (c) 2012-2014                                                               *
 *                                                                                *
 * 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.                                         *
 ****************************************************************************************/

#if !defined(WIN32) && !defined(__APPLE__)
#include <ghoul/filesystem/filesystem.h>

#include <ghoul/filesystem/cachemanager.h>
#include <ghoul/logging/logmanager.h>

#include <algorithm>
#include <cassert>
#include <regex>
#include <cstdio>

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

#include <sys/inotify.h>
#define EVENT_SIZE  ( sizeof (struct inotify_event) )
#define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )

using std::string;

namespace {
    const string _loggerCat = "FileSystem";
	const uint32_t mask = IN_ALL_EVENTS | IN_IGNORED | IN_Q_OVERFLOW | IN_UNMOUNT | IN_ISDIR;
}

namespace ghoul {
namespace filesystem {

void FileSystem::initializeInternalLinux() {
    _inotifyHandle = inotify_init();
    _keepGoing = true;
    _t = std::thread(inotifyWatcher);
}

void FileSystem::deinitializeInternalLinux() {
	_keepGoing = false;
	if (_t.joinable())
		_t.join();
	close(_inotifyHandle);
}

void FileSystem::addFileListener(File* file) {
	assert(file != nullptr);
	const std::string filename = file->path();
	int wd = inotify_add_watch(_inotifyHandle, filename.c_str(), mask);
    auto eqRange = _trackedFiles.equal_range(wd);
    for (auto it = eqRange.first; it != eqRange.second; ++it) {
        if (it.second == file) {
            LERROR("Already tracking fileobject");
            return;
        }
    }
	_trackedFiles.emplace(wd, file);
}

void FileSystem::removeFileListener(File* file) {
	assert(file != nullptr);

    const std::string filename = file->path();
    int wd = inotify_add_watch(_inotifyHandle, filename.c_str(), mask);
    int count = _trackedFiles.count(wd);
    auto eqRange = _trackedFiles.equal_range(wd);
    for (auto it = eqRange.first; it != eqRange.second; ++it) {
        if (it.second == file) {
            if(count == 1)
                ( void ) inotify_rm_watch( _inotifyHandle, it.first );
            _trackedFiles.erase(it);
            return;
        }
    }
    LWARNING("Could not find tracked '" << file <<"' for path '"<< file->path() << "'");
}

void FileSystem::inotifyWatcher() {

	int fd = FileSys._inotifyHandle;
    char buffer[BUF_LEN];
    struct timeval tv;
    tv.tv_sec = 1;
    tv.tv_usec = 0;
    fd_set rfds;
    while(FileSys._keepGoing) {
        FD_ZERO (&rfds);
        FD_SET (fd, &rfds);
        if(select (FD_SETSIZE, &rfds, NULL, NULL, &tv) < 1) continue;

        int length = read( fd, buffer, BUF_LEN );
        if ( length < 0 ) continue;

        int offset = 0;
        while (offset < length) {
            struct inotify_event *event = (inotify_event*)(buffer + offset);
            switch (event->mask )
            {

                case IN_MODIFY:
                case IN_ATTRIB:
                {
                    int wd = event->wd;
                    auto eqRange = FileSys._trackedFiles.equal_range(wd);
                    for (auto it = eqRange.first; it != eqRange.second; ++it) {
                        File* fileobject = it->second;
                        fileobject->_fileChangedCallback(*fileobject);
                    }

                }

                    break;

                case IN_IGNORED:
                {
                    int wd = event->wd;

                    auto eqRange = FileSys._trackedFiles.equal_range(wd);
                    auto it = eqRange.first;

                    // remove tracking of the removed descriptor
                    ( void ) inotify_rm_watch( fd, wd );

                    // if there are files tracking
                    if(it != eqRange.second) {
                        // add new tracking
                        int new_wd = inotify_add_watch( fd, it->second->path().c_str(), mask);

                        // save all files
                        std::vector<File*> v;
                        for (;it != eqRange.second; ++it) {
                            v.push_back(it->second);
                        }

                        // erase all previous files and add them again
                        FileSys._trackedFiles.erase(eqRange.first, eqRange.second);
                        for(auto f: v) {
                            FileSys._trackedFiles.emplace(new_wd, f);
                        }
                    }

                }
                    //printf ("IN_IGNORED\n");
                    break;
                default:
                    break;
            }
            offset += EVENT_SIZE + event->len;
        }
    }
}

} // namespace filesystem
} // namespace ghoul

#endif

<commit_msg>Revert changes in linux filesystem<commit_after>/*****************************************************************************************
 *                                                                                *
 * GHOUL                                                                                *
 * General Helpful Open Utility Library                                                  *
 *                                                                                *
 * Copyright (c) 2012-2014                                                               *
 *                                                                                *
 * 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.                                         *
 ****************************************************************************************/

#if !defined(WIN32) && !defined(__APPLE__)
#include <ghoul/filesystem/filesystem.h>

#include <ghoul/filesystem/cachemanager.h>
#include <ghoul/logging/logmanager.h>

#include <algorithm>
#include <cassert>
#include <regex>
#include <cstdio>

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

#include <sys/inotify.h>
#define EVENT_SIZE  ( sizeof (struct inotify_event) )
#define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )

using std::string;

namespace {
    const string _loggerCat = "FileSystem";
	const uint32_t mask = IN_ALL_EVENTS | IN_IGNORED | IN_Q_OVERFLOW | IN_UNMOUNT | IN_ISDIR;
}

namespace ghoul {
namespace filesystem {

void FileSystem::initializeInternalLinux() {
    _inotifyHandle = inotify_init();
    _keepGoing = true;
    _t = std::thread(inotifyWatcher);
}

void FileSystem::deinitializeInternalLinux() {
	_keepGoing = false;
	if (_t.joinable())
		_t.join();
	close(_inotifyHandle);
}

void FileSystem::addFileListener(File* file) {
	assert(file != nullptr);
	const std::string filename = file->path();
	int wd = inotify_add_watch(_inotifyHandle, filename.c_str(), mask);
    auto eqRange = _trackedFiles.equal_range(wd);
    for (auto it = eqRange.first; it != eqRange.second; ++it) {
        if (it->second == file) {
            LERROR("Already tracking fileobject");
            return;
        }
    }
	_trackedFiles.emplace(wd, file);
}

void FileSystem::removeFileListener(File* file) {
	assert(file != nullptr);

    const std::string filename = file->path();
    int wd = inotify_add_watch(_inotifyHandle, filename.c_str(), mask);
    int count = _trackedFiles.count(wd);
    auto eqRange = _trackedFiles.equal_range(wd);
    for (auto it = eqRange.first; it != eqRange.second; ++it) {
        if (it->second == file) {
            if(count == 1)
                ( void ) inotify_rm_watch( _inotifyHandle, it->first );
            _trackedFiles.erase(it);
            return;
        }
    }
    LWARNING("Could not find tracked '" << file <<"' for path '"<< file->path() << "'");
}

void FileSystem::inotifyWatcher() {

	int fd = FileSys._inotifyHandle;
    char buffer[BUF_LEN];
    struct timeval tv;
    tv.tv_sec = 1;
    tv.tv_usec = 0;
    fd_set rfds;
    while(FileSys._keepGoing) {
        FD_ZERO (&rfds);
        FD_SET (fd, &rfds);
        if(select (FD_SETSIZE, &rfds, NULL, NULL, &tv) < 1) continue;

        int length = read( fd, buffer, BUF_LEN );
        if ( length < 0 ) continue;

        int offset = 0;
        while (offset < length) {
            struct inotify_event *event = (inotify_event*)(buffer + offset);
            switch (event->mask )
            {

                case IN_MODIFY:
                case IN_ATTRIB:
                {
                    int wd = event->wd;
                    auto eqRange = FileSys._trackedFiles.equal_range(wd);
                    for (auto it = eqRange.first; it != eqRange.second; ++it) {
                        File* fileobject = it->second;
                        fileobject->_fileChangedCallback(*fileobject);
                    }

                }

                    break;

                case IN_IGNORED:
                {
                    int wd = event->wd;

                    auto eqRange = FileSys._trackedFiles.equal_range(wd);
                    auto it = eqRange.first;

                    // remove tracking of the removed descriptor
                    ( void ) inotify_rm_watch( fd, wd );

                    // if there are files tracking
                    if(it != eqRange.second) {
                        // add new tracking
                        int new_wd = inotify_add_watch( fd, it->second->path().c_str(), mask);

                        // save all files
                        std::vector<File*> v;
                        for (;it != eqRange.second; ++it) {
                            v.push_back(it->second);
                        }

                        // erase all previous files and add them again
                        FileSys._trackedFiles.erase(eqRange.first, eqRange.second);
                        for(auto f: v) {
                            FileSys._trackedFiles.emplace(new_wd, f);
                        }
                    }

                }
                    //printf ("IN_IGNORED\n");
                    break;
                default:
                    break;
            }
            offset += EVENT_SIZE + event->len;
        }
    }
}

} // namespace filesystem
} // namespace ghoul

#endif

<|endoftext|>


<commit_before>//
// Created by Zal on 11/19/16.
//

#include <assert.h>
#include <utility>
#include "BinaryMatrix.h"

void BinaryMatrix::BinaryMatrix(int w, int h) {
    this->width = w;
    this->height = h;
    baseSize = sizeof(char);

    int n = w*h;
    this->dataLength = (n % baseSize == 0)? n/baseSize : n/baseSize +1;
    this->data = new char[dataLength];
}

void BinaryMatrix::~BinaryMatrix() {
    delete[] data;
}

void BinaryMatrix::T() {
    this->transposed = !this->transposed;
}

BinaryMatrix BinaryMatrix::binMultiply(const BinaryMatrix& other) {
    BinaryMatrix res(this->width, this->height);
    for(int i = 0; i < this->dataLength; ++i) {
        res.data[i] = !(this->data[i] ^ other.data[i]);
    }
    return res;
}

std::pair<int, int> elem_accessor(int i, int rows, int cols, bool transposed) {
    if (transposed) {
        return std::make_pair(i % rows, i / rows);
    } else {
        return std::make_pair(i / cols, i % cols);
    }
}

char get_bit(char elem, int bit_id) {
    char mask = 1 << (8 - bit_id);
    return (elem & mask) >> (8 - bit_id);
}

char set_bit(char elem, int bit_id, char bit) {
    // assumes originally the bit is set to 0
    char mask = 1 << (8 - bit_id);
    char new_elem = (elem | (bit << mask));
    return new_elem;
}

BinaryMatrix BinaryMatrix::tBinMultiply(const BinaryMatrix& other) {
    int w = this->width;
    int h = this->height;
    if (this->transposed) {
        w = other.width;
        h = other.height;
    }
    int this_n = this->dataLength;
    int other_n = other.dataLength;
    BinaryMatrix res(w, h);
    for (int bit_id = 0; bit_id < (w * h); ++bit_id) {
        std::pair<int, int> this_rc = elem_accessor(bit_id, this_n, 8 this->transposed);
        std::pair<int, int> other_rc = elem_accessor(bit_id, other_n, 8, other.transposed);
        std::pair<int, int> res_rc = elem_accessor(bit_Id, res.dataLength, 8, res.transposed);
        char this_c = this->data[this_rc.first];
        char other_c = other.data[other_rc.first];
        char res_c = res.data[res_rc.first];

        char answer = (!(get_bit(this_c, this_rc.second) ^ get_bit(other_c, other_rc.second)))
                        & 0x0001;
        res.data[res_rc.first] = set_bit(res_c, res_rc.second, answer);
    }
    return res;
}

double BinaryMatrix::doubleMultiply(const double& other) {

}

BinaryMatrix BinaryMatrix::operator*(const BinaryMatrix& other ) {
    if(this->transposed != other.transposed) {
        assert(this->width == other.height);
        assert(this->height == other.width);
        return this->tBinMultiply(other);
    }
    else {
        assert(this->width == other.width);
        assert(this->height == other.height);
        return this->binMultiply(other);
    }
}
<commit_msg>Generalized to base size for bit shifting and accessing<commit_after>//
// Created by Zal on 11/19/16.
//

#include <assert.h>
#include <utility>
#include "BinaryMatrix.h"

void BinaryMatrix::BinaryMatrix(int w, int h) {
    this->width = w;
    this->height = h;
    this->baseSize = sizeof(char) * 8;

    int n = w*h;
    this->dataLength = (n % baseSize == 0)? n/baseSize : n/baseSize +1;
    this->data = new char[dataLength];
}

void BinaryMatrix::~BinaryMatrix() {
    delete[] data;
}

void BinaryMatrix::T() {
    this->transposed = !this->transposed;
}

BinaryMatrix BinaryMatrix::binMultiply(const BinaryMatrix& other) {
    BinaryMatrix res(this->width, this->height);
    for(int i = 0; i < this->dataLength; ++i) {
        res.data[i] = !(this->data[i] ^ other.data[i]);
    }
    return res;
}

std::pair<int, int> elem_accessor(int i, int rows, int cols, bool transposed) {
    if (transposed) {
        return std::make_pair(i % rows, i / rows);
    } else {
        return std::make_pair(i / cols, i % cols);
    }
}

char get_bit(char elem, int bit_id) {
    return (elem >> (this->baseSize - bit_id)) & 1;
}

char set_bit(char elem, int bit_id, char bit) {
    // assumes originally the bit is set to 0
    char mask = 1 << ( - bit_id);
    char new_elem = (elem | (bit << mask));
    return new_elem;
}

BinaryMatrix BinaryMatrix::tBinMultiply(const BinaryMatrix& other) {
    int w = this->width;
    int h = this->height;
    if (this->transposed) {
        w = other.width;
        h = other.height;
    }
    int this_n = this->dataLength;
    int other_n = other.dataLength;
    int res_n = res.dataLength;
    BinaryMatrix res(w, h);
    for (int bit_id = 0; bit_id < (w * h); ++bit_id) {
        std::pair<int, int> this_rc = elem_accessor(bit_id, this_n, this->baseSize, this->transposed);
        std::pair<int, int> other_rc = elem_accessor(bit_id, other_n, this->baseSize, other.transposed);
        std::pair<int, int> res_rc = elem_accessor(bit_Id, res_n, this->baseSize, res.transposed);
        char this_c = this->data[this_rc.first];
        char other_c = other.data[other_rc.first];
        char res_c = res.data[res_rc.first];

        char answer = !(get_bit(this_c, this_rc.second) ^ get_bit(other_c, other_rc.second)) & 1;
        res.data[res_rc.first] = set_bit(res_c, res_rc.second, answer);
    }
    return res;
}

double BinaryMatrix::doubleMultiply(const double& other) {

}

BinaryMatrix BinaryMatrix::operator*(const BinaryMatrix& other ) {
    if(this->transposed != other.transposed) {
        assert(this->width == other.height);
        assert(this->height == other.width);
        return this->tBinMultiply(other);
    }
    else {
        assert(this->width == other.width);
        assert(this->height == other.height);
        return this->binMultiply(other);
    }
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2015 Olavi Haapala.
<ojhaapala@gmail.com>
Twitter: @olpetik
IRC: olpe
All rights reserved.

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

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

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

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

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

#ifdef QT_QML_DEBUG
#include <QtQuick>
#endif

#include <sailfishapp.h>
#include <QSettings>
#include <QQuickWindow>
#include <QGuiApplication>
#include <QQuickView>
#include <QQmlContext>
#include <QDebug>
#include <QFileInfo>

#include "SettingsClass.h"
#include "Launcher.h"
#include "Exporter.h"
#include "Logger.h"

int main(int argc, char *argv[])
{
    // Make sure the logger is initialized
    Logger::instance();

    Settings settings;
    Launcher launcher;
    Exporter exporter;
    QScopedPointer<QGuiApplication> app(SailfishApp::application(argc, argv));
    app->setApplicationName("harbour-workinghourstracker");

    QQuickWindow::setDefaultAlphaBuffer(true);
    QScopedPointer<QQuickView> view(SailfishApp::createView());
    view->rootContext()->setContextProperty("settings", &settings);
    view->rootContext()->setContextProperty("launcher", &launcher);
    view->rootContext()->setContextProperty("exporter", &exporter);

    view->rootContext()->setContextProperty("Log", &Logger::instance());

    view->setSource(SailfishApp::pathTo("qml/harbour-workinghourstracker.qml"));
    view->setResizeMode(QQuickView::SizeRootObjectToView);
    view->show();
    return app->exec();
}
<commit_msg>prep for release<commit_after>/*
Copyright (C) 2015 Olavi Haapala.
<ojhaapala@gmail.com>
Twitter: @olpetik
IRC: olpe
All rights reserved.

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

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

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

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

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

#ifdef QT_QML_DEBUG
#include <QtQuick>
#endif

#include <sailfishapp.h>
#include <QSettings>
#include <QQuickWindow>
#include <QGuiApplication>
#include <QQuickView>
#include <QQmlContext>
#include <QDebug>
#include <QFileInfo>
#include <QStandardPaths>

#include "SettingsClass.h"
#include "Launcher.h"
#include "Exporter.h"
#include "Logger.h"

int main(int argc, char *argv[])
{
    // Make sure the logger is initialized
    Logger::instance();

    Settings settings;
    Launcher launcher;
    Exporter exporter;
    QScopedPointer<QGuiApplication> app(SailfishApp::application(argc, argv));
    app->setApplicationName("harbour-workinghourstracker");
    QCoreApplication::setApplicationName("harbour-workinghourstracker");

    QQuickWindow::setDefaultAlphaBuffer(true);
    QScopedPointer<QQuickView> view(SailfishApp::createView());
    view->rootContext()->setContextProperty("settings", &settings);
    view->rootContext()->setContextProperty("launcher", &launcher);
    view->rootContext()->setContextProperty("exporter", &exporter);

    view->rootContext()->setContextProperty("Log", &Logger::instance());
    view->rootContext()->setContextProperty("documentsLocation",QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));

    view->setSource(SailfishApp::pathTo("qml/harbour-workinghourstracker.qml"));
    view->setResizeMode(QQuickView::SizeRootObjectToView);
    view->show();
    return app->exec();
}
<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2018 Advanced Micro Devices, Inc.
* Copyright (c) 2018 The Khronos Group 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.
*
*//*!
* \file
* \brief VK_KHR_driver_properties tests
*//*--------------------------------------------------------------------*/

#include "vktApiDriverPropertiesTests.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkKnownDriverIds.inl"

using namespace vk;

namespace vkt
{
namespace api
{
namespace
{

enum TestType
{
	TEST_TYPE_DRIVER_ID_MATCH			= 0,
	TEST_TYPE_NAME_IS_NOT_EMPTY,
	TEST_TYPE_NAME_ZERO_TERMINATED,
	TEST_TYPE_INFO_ZERO_TERMINATED,
	TEST_TYPE_VERSION,
};

static const VkConformanceVersionKHR knownConformanceVersions[] =
{
	makeConformanceVersion(1, 3, 1, 0),
	makeConformanceVersion(1, 3, 0, 0),
	makeConformanceVersion(1, 2, 8, 0),
	makeConformanceVersion(1, 2, 7, 2),
	makeConformanceVersion(1, 2, 7, 1),
	makeConformanceVersion(1, 2, 7, 0),
	makeConformanceVersion(1, 2, 6, 2),
	makeConformanceVersion(1, 2, 6, 1),
	makeConformanceVersion(1, 2, 6, 0),
	makeConformanceVersion(1, 2, 5, 2),
	makeConformanceVersion(1, 2, 5, 1),
	makeConformanceVersion(1, 2, 5, 0),
	makeConformanceVersion(1, 2, 4, 1),
	makeConformanceVersion(1, 2, 4, 0),
	makeConformanceVersion(1, 2, 3, 3),
	makeConformanceVersion(1, 2, 3, 2),
	makeConformanceVersion(1, 2, 3, 1),
	makeConformanceVersion(1, 2, 3, 0),
	makeConformanceVersion(1, 2, 2, 2),
	makeConformanceVersion(1, 2, 2, 1),
	makeConformanceVersion(1, 2, 2, 0),
	makeConformanceVersion(1, 2, 1, 2),
	makeConformanceVersion(1, 2, 1, 1),
	makeConformanceVersion(1, 2, 1, 0),
	makeConformanceVersion(1, 2, 0, 2),
	makeConformanceVersion(1, 2, 0, 1),
	makeConformanceVersion(1, 2, 0, 0),
	makeConformanceVersion(1, 1, 6, 3),
	makeConformanceVersion(1, 1, 6, 2),
	makeConformanceVersion(1, 1, 6, 1),
	makeConformanceVersion(1, 1, 6, 0),
	makeConformanceVersion(1, 1, 5, 2),
	makeConformanceVersion(1, 1, 5, 1),
	makeConformanceVersion(1, 1, 5, 0),
	makeConformanceVersion(1, 1, 4, 3),
	makeConformanceVersion(1, 1, 4, 2),
	makeConformanceVersion(1, 1, 4, 1),
	makeConformanceVersion(1, 1, 4, 0),
	makeConformanceVersion(1, 1, 3, 3),
	makeConformanceVersion(1, 1, 3, 2),
	makeConformanceVersion(1, 1, 3, 1),
	makeConformanceVersion(1, 1, 3, 0),
};

DE_INLINE bool isNullTerminated(const char* str, const deUint32 maxSize)
{
	return deStrnlen(str, maxSize) < maxSize;
}

DE_INLINE bool operator==(const VkConformanceVersion& a, const VkConformanceVersion& b)
{
	return ((a.major == b.major)		&&
			(a.minor == b.minor)		&&
			(a.subminor == b.subminor)	&&
			(a.patch == b.patch));
}

void checkSupport (Context& context, const TestType config)
{
	DE_UNREF(config);
	context.requireDeviceFunctionality("VK_KHR_driver_properties");
}

void testDriverMatch (const VkPhysicalDeviceDriverPropertiesKHR& deviceDriverProperties)
{
	for (deUint32 driverNdx = 0; driverNdx < DE_LENGTH_OF_ARRAY(driverIds); driverNdx++)
	{
		if (deviceDriverProperties.driverID == driverIds[driverNdx].id)
			return;
	}

	TCU_FAIL("Driver ID did not match any known driver");
}

void testNameIsNotEmpty (const VkPhysicalDeviceDriverPropertiesKHR& deviceDriverProperties)
{
	if (deviceDriverProperties.driverName[0] == 0)
		TCU_FAIL("Driver name is empty");
}

void testNameZeroTerminated (const VkPhysicalDeviceDriverPropertiesKHR& deviceDriverProperties)
{
	if (!isNullTerminated(deviceDriverProperties.driverName, VK_MAX_DRIVER_NAME_SIZE_KHR))
		TCU_FAIL("Driver name is not a null-terminated string");
}

void testInfoZeroTerminated (const VkPhysicalDeviceDriverPropertiesKHR& deviceDriverProperties)
{
	if (!isNullTerminated(deviceDriverProperties.driverInfo, VK_MAX_DRIVER_INFO_SIZE_KHR))
		TCU_FAIL("Driver info is not a null-terminated string");
}

void testVersion (const VkPhysicalDeviceDriverPropertiesKHR& deviceDriverProperties, deUint32 usedApiVersion)
{
	const deUint32 apiMajorVersion = VK_API_VERSION_MAJOR(usedApiVersion);
	const deUint32 apiMinorVersion = VK_API_VERSION_MINOR(usedApiVersion);

	if (deviceDriverProperties.conformanceVersion.major < apiMajorVersion ||
		(deviceDriverProperties.conformanceVersion.major == apiMajorVersion &&
		 deviceDriverProperties.conformanceVersion.minor < apiMinorVersion))
	{
		TCU_FAIL("Wrong driver conformance version (older than used API version)");
	}

	for (const VkConformanceVersionKHR* pConformanceVersion  = knownConformanceVersions;
										pConformanceVersion != DE_ARRAY_END(knownConformanceVersions);
									  ++pConformanceVersion)
	{
		if (deviceDriverProperties.conformanceVersion == *pConformanceVersion)
			return;
	}

	TCU_FAIL("Wrong driver conformance version (not known)");
}

tcu::TestStatus testQueryProperties (Context& context, const TestType testType)
{
	// Query the driver properties
	const VkPhysicalDevice				physDevice			= context.getPhysicalDevice();
	const int							memsetPattern		= 0xaa;
	VkPhysicalDeviceProperties2			deviceProperties2;
	VkPhysicalDeviceDriverProperties	deviceDriverProperties;

	deMemset(&deviceDriverProperties, memsetPattern, sizeof(deviceDriverProperties));
	deviceDriverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
	deviceDriverProperties.pNext = DE_NULL;

	deMemset(&deviceProperties2, memsetPattern, sizeof(deviceProperties2));
	deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
	deviceProperties2.pNext = &deviceDriverProperties;

	context.getInstanceInterface().getPhysicalDeviceProperties2(physDevice, &deviceProperties2);

	// Verify the returned values
	switch (testType)
	{
		case TEST_TYPE_DRIVER_ID_MATCH:			testDriverMatch			(deviceDriverProperties);								break;
		case TEST_TYPE_NAME_IS_NOT_EMPTY:		testNameIsNotEmpty		(deviceDriverProperties);								break;
		case TEST_TYPE_NAME_ZERO_TERMINATED:	testNameZeroTerminated	(deviceDriverProperties);								break;
		case TEST_TYPE_INFO_ZERO_TERMINATED:	testInfoZeroTerminated	(deviceDriverProperties);								break;
		case TEST_TYPE_VERSION:					testVersion				(deviceDriverProperties, context.getUsedApiVersion());	break;
		default:								TCU_THROW(InternalError, "Unknown test type specified");
	}

	return tcu::TestStatus::pass("Pass");
}

void createTestCases (tcu::TestCaseGroup* group)
{
	addFunctionCase(group, "driver_id_match",		"Check driverID is supported",					checkSupport,	testQueryProperties,	TEST_TYPE_DRIVER_ID_MATCH);
	addFunctionCase(group, "name_is_not_empty",		"Check name field is not empty",				checkSupport,	testQueryProperties,	TEST_TYPE_NAME_IS_NOT_EMPTY);
	addFunctionCase(group, "name_zero_terminated",	"Check name field is zero-terminated",			checkSupport,	testQueryProperties,	TEST_TYPE_NAME_ZERO_TERMINATED);
	addFunctionCase(group, "info_zero_terminated",	"Check info field is zero-terminated",			checkSupport,	testQueryProperties,	TEST_TYPE_INFO_ZERO_TERMINATED);
	addFunctionCase(group, "conformance_version",	"Check conformanceVersion reported by driver",	checkSupport,	testQueryProperties,	TEST_TYPE_VERSION);
}

} // anonymous

tcu::TestCaseGroup*	createDriverPropertiesTests(tcu::TestContext& testCtx)
{
	return createTestGroup(testCtx, "driver_properties", "VK_KHR_driver_properties tests", createTestCases);
}

} // api
} // vkt
<commit_msg>Update known conformance version for 1.3.1.1<commit_after>/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2018 Advanced Micro Devices, Inc.
* Copyright (c) 2018 The Khronos Group 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.
*
*//*!
* \file
* \brief VK_KHR_driver_properties tests
*//*--------------------------------------------------------------------*/

#include "vktApiDriverPropertiesTests.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkKnownDriverIds.inl"

using namespace vk;

namespace vkt
{
namespace api
{
namespace
{

enum TestType
{
	TEST_TYPE_DRIVER_ID_MATCH			= 0,
	TEST_TYPE_NAME_IS_NOT_EMPTY,
	TEST_TYPE_NAME_ZERO_TERMINATED,
	TEST_TYPE_INFO_ZERO_TERMINATED,
	TEST_TYPE_VERSION,
};

static const VkConformanceVersionKHR knownConformanceVersions[] =
{
	makeConformanceVersion(1, 3, 1, 1),
	makeConformanceVersion(1, 3, 1, 0),
	makeConformanceVersion(1, 3, 0, 0),
	makeConformanceVersion(1, 2, 8, 0),
	makeConformanceVersion(1, 2, 7, 2),
	makeConformanceVersion(1, 2, 7, 1),
	makeConformanceVersion(1, 2, 7, 0),
	makeConformanceVersion(1, 2, 6, 2),
	makeConformanceVersion(1, 2, 6, 1),
	makeConformanceVersion(1, 2, 6, 0),
	makeConformanceVersion(1, 2, 5, 2),
	makeConformanceVersion(1, 2, 5, 1),
	makeConformanceVersion(1, 2, 5, 0),
	makeConformanceVersion(1, 2, 4, 1),
	makeConformanceVersion(1, 2, 4, 0),
	makeConformanceVersion(1, 2, 3, 3),
	makeConformanceVersion(1, 2, 3, 2),
	makeConformanceVersion(1, 2, 3, 1),
	makeConformanceVersion(1, 2, 3, 0),
	makeConformanceVersion(1, 2, 2, 2),
	makeConformanceVersion(1, 2, 2, 1),
	makeConformanceVersion(1, 2, 2, 0),
	makeConformanceVersion(1, 2, 1, 2),
	makeConformanceVersion(1, 2, 1, 1),
	makeConformanceVersion(1, 2, 1, 0),
	makeConformanceVersion(1, 2, 0, 2),
	makeConformanceVersion(1, 2, 0, 1),
	makeConformanceVersion(1, 2, 0, 0),
	makeConformanceVersion(1, 1, 6, 3),
	makeConformanceVersion(1, 1, 6, 2),
	makeConformanceVersion(1, 1, 6, 1),
	makeConformanceVersion(1, 1, 6, 0),
	makeConformanceVersion(1, 1, 5, 2),
	makeConformanceVersion(1, 1, 5, 1),
	makeConformanceVersion(1, 1, 5, 0),
	makeConformanceVersion(1, 1, 4, 3),
	makeConformanceVersion(1, 1, 4, 2),
	makeConformanceVersion(1, 1, 4, 1),
	makeConformanceVersion(1, 1, 4, 0),
	makeConformanceVersion(1, 1, 3, 3),
	makeConformanceVersion(1, 1, 3, 2),
	makeConformanceVersion(1, 1, 3, 1),
	makeConformanceVersion(1, 1, 3, 0),
};

DE_INLINE bool isNullTerminated(const char* str, const deUint32 maxSize)
{
	return deStrnlen(str, maxSize) < maxSize;
}

DE_INLINE bool operator==(const VkConformanceVersion& a, const VkConformanceVersion& b)
{
	return ((a.major == b.major)		&&
			(a.minor == b.minor)		&&
			(a.subminor == b.subminor)	&&
			(a.patch == b.patch));
}

void checkSupport (Context& context, const TestType config)
{
	DE_UNREF(config);
	context.requireDeviceFunctionality("VK_KHR_driver_properties");
}

void testDriverMatch (const VkPhysicalDeviceDriverPropertiesKHR& deviceDriverProperties)
{
	for (deUint32 driverNdx = 0; driverNdx < DE_LENGTH_OF_ARRAY(driverIds); driverNdx++)
	{
		if (deviceDriverProperties.driverID == driverIds[driverNdx].id)
			return;
	}

	TCU_FAIL("Driver ID did not match any known driver");
}

void testNameIsNotEmpty (const VkPhysicalDeviceDriverPropertiesKHR& deviceDriverProperties)
{
	if (deviceDriverProperties.driverName[0] == 0)
		TCU_FAIL("Driver name is empty");
}

void testNameZeroTerminated (const VkPhysicalDeviceDriverPropertiesKHR& deviceDriverProperties)
{
	if (!isNullTerminated(deviceDriverProperties.driverName, VK_MAX_DRIVER_NAME_SIZE_KHR))
		TCU_FAIL("Driver name is not a null-terminated string");
}

void testInfoZeroTerminated (const VkPhysicalDeviceDriverPropertiesKHR& deviceDriverProperties)
{
	if (!isNullTerminated(deviceDriverProperties.driverInfo, VK_MAX_DRIVER_INFO_SIZE_KHR))
		TCU_FAIL("Driver info is not a null-terminated string");
}

void testVersion (const VkPhysicalDeviceDriverPropertiesKHR& deviceDriverProperties, deUint32 usedApiVersion)
{
	const deUint32 apiMajorVersion = VK_API_VERSION_MAJOR(usedApiVersion);
	const deUint32 apiMinorVersion = VK_API_VERSION_MINOR(usedApiVersion);

	if (deviceDriverProperties.conformanceVersion.major < apiMajorVersion ||
		(deviceDriverProperties.conformanceVersion.major == apiMajorVersion &&
		 deviceDriverProperties.conformanceVersion.minor < apiMinorVersion))
	{
		TCU_FAIL("Wrong driver conformance version (older than used API version)");
	}

	for (const VkConformanceVersionKHR* pConformanceVersion  = knownConformanceVersions;
										pConformanceVersion != DE_ARRAY_END(knownConformanceVersions);
									  ++pConformanceVersion)
	{
		if (deviceDriverProperties.conformanceVersion == *pConformanceVersion)
			return;
	}

	TCU_FAIL("Wrong driver conformance version (not known)");
}

tcu::TestStatus testQueryProperties (Context& context, const TestType testType)
{
	// Query the driver properties
	const VkPhysicalDevice				physDevice			= context.getPhysicalDevice();
	const int							memsetPattern		= 0xaa;
	VkPhysicalDeviceProperties2			deviceProperties2;
	VkPhysicalDeviceDriverProperties	deviceDriverProperties;

	deMemset(&deviceDriverProperties, memsetPattern, sizeof(deviceDriverProperties));
	deviceDriverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
	deviceDriverProperties.pNext = DE_NULL;

	deMemset(&deviceProperties2, memsetPattern, sizeof(deviceProperties2));
	deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
	deviceProperties2.pNext = &deviceDriverProperties;

	context.getInstanceInterface().getPhysicalDeviceProperties2(physDevice, &deviceProperties2);

	// Verify the returned values
	switch (testType)
	{
		case TEST_TYPE_DRIVER_ID_MATCH:			testDriverMatch			(deviceDriverProperties);								break;
		case TEST_TYPE_NAME_IS_NOT_EMPTY:		testNameIsNotEmpty		(deviceDriverProperties);								break;
		case TEST_TYPE_NAME_ZERO_TERMINATED:	testNameZeroTerminated	(deviceDriverProperties);								break;
		case TEST_TYPE_INFO_ZERO_TERMINATED:	testInfoZeroTerminated	(deviceDriverProperties);								break;
		case TEST_TYPE_VERSION:					testVersion				(deviceDriverProperties, context.getUsedApiVersion());	break;
		default:								TCU_THROW(InternalError, "Unknown test type specified");
	}

	return tcu::TestStatus::pass("Pass");
}

void createTestCases (tcu::TestCaseGroup* group)
{
	addFunctionCase(group, "driver_id_match",		"Check driverID is supported",					checkSupport,	testQueryProperties,	TEST_TYPE_DRIVER_ID_MATCH);
	addFunctionCase(group, "name_is_not_empty",		"Check name field is not empty",				checkSupport,	testQueryProperties,	TEST_TYPE_NAME_IS_NOT_EMPTY);
	addFunctionCase(group, "name_zero_terminated",	"Check name field is zero-terminated",			checkSupport,	testQueryProperties,	TEST_TYPE_NAME_ZERO_TERMINATED);
	addFunctionCase(group, "info_zero_terminated",	"Check info field is zero-terminated",			checkSupport,	testQueryProperties,	TEST_TYPE_INFO_ZERO_TERMINATED);
	addFunctionCase(group, "conformance_version",	"Check conformanceVersion reported by driver",	checkSupport,	testQueryProperties,	TEST_TYPE_VERSION);
}

} // anonymous

tcu::TestCaseGroup*	createDriverPropertiesTests(tcu::TestContext& testCtx)
{
	return createTestGroup(testCtx, "driver_properties", "VK_KHR_driver_properties tests", createTestCases);
}

} // api
} // vkt
<|endoftext|>