<commit_before>#include "Histogram1DDataBlock.h"

#include "RasterDataBlock.h"
using namespace std;
using namespace UVFTables;

Histogram1DDataBlock::Histogram1DDataBlock() : DataBlock() {
  ulBlockSemantics = BS_1D_HISTOGRAM;
  strBlockID       = "1D Histogram";
}

Histogram1DDataBlock::Histogram1DDataBlock(const Histogram1DDataBlock &other) :
  DataBlock(other),
  m_vHistData(other.m_vHistData)
{
}

Histogram1DDataBlock& Histogram1DDataBlock::operator=(const Histogram1DDataBlock& other) {
  strBlockID = other.strBlockID;
  ulBlockSemantics = other.ulBlockSemantics;
  ulCompressionScheme = other.ulCompressionScheme;
  ulOffsetToNextDataBlock = other.ulOffsetToNextDataBlock;

  m_vHistData = other.m_vHistData;

  return *this;
}

Histogram1DDataBlock::Histogram1DDataBlock(LargeRAWFile* pStreamFile, UINT64 iOffset, bool bIsBigEndian) {
  GetHeaderFromFile(pStreamFile, iOffset, bIsBigEndian);
}

Histogram1DDataBlock::~Histogram1DDataBlock()
{
}

DataBlock* Histogram1DDataBlock::Clone() const {
  return new Histogram1DDataBlock(*this);
}

UINT64 Histogram1DDataBlock::GetHeaderFromFile(LargeRAWFile* pStreamFile, UINT64 iOffset, bool bIsBigEndian) {
  UINT64 iStart = iOffset + DataBlock::GetHeaderFromFile(pStreamFile, iOffset, bIsBigEndian);
  pStreamFile->SeekPos(iStart);

  UINT64 ulElementCount;
  pStreamFile->ReadData(ulElementCount, bIsBigEndian);

  m_vHistData.resize(size_t(ulElementCount));
  pStreamFile->ReadRAW((unsigned char*)&m_vHistData[0], ulElementCount*sizeof(UINT64));
  return pStreamFile->GetPos() - iOffset;
}

bool Histogram1DDataBlock::Compute(const RasterDataBlock* source) {

  // TODO: right now we can only compute Histograms of scalar data this should be changed to a more general approach
  if (source->ulElementDimension != 1 || source->ulElementDimensionSize.size() != 1) return false;

  /// \todo right now compute Histogram assumes that at least the lowest LOD level consists only
  //       of a single brick, this brick is used for the hist.-computation
  //       this should be changed to a more general approach
  vector<UINT64> vSmallestLOD = source->GetSmallestBrickIndex();
  const vector<UINT64>& vBricks = source->GetBrickCount(vSmallestLOD);
  for (size_t i = 0;i<vBricks.size();i++) if (vBricks[i] != 1) return false;

  // create temp histogram
  size_t iValueRange = size_t(1<<(source->ulElementBitSize[0][0]));
  vector<UINT64> vTmpHist(iValueRange);
  if (vTmpHist.size() != iValueRange) return false;
  for (size_t i = 0;i<iValueRange;i++) vTmpHist[i] = 0;

  // LargestSingleBrickLODBrickIndex is well defined as we tested above if we have a single brick LOD
  std::vector<unsigned char> vcSourceData;
  vector<UINT64> vLOD = source->LargestSingleBrickLODBrickIndex();
  vector<UINT64> vOneAndOnly;
  for (size_t i = 0;i<vBricks.size();i++) vOneAndOnly.push_back(0);
  if (!source->GetData(vcSourceData, vLOD, vOneAndOnly)) return false;

  vector<UINT64> vSize  = source->LargestSingleBrickLODBrickSize();

  UINT64 iDataSize = 1;
  for (size_t i = 0;i<vSize.size();i++) iDataSize*=vSize[i];

  /// @todo only 8 and 16 bit integer data are supported.  this should be
  ///       changed to use a more general approach.
  if (source->ulElementBitSize[0][0] == 8) {
    for (UINT64 i = 0;i<iDataSize;i++) {
       vTmpHist[vcSourceData[size_t(i)]]++;
    }
  } else {
    if (source->ulElementBitSize[0][0] == 16) {
      unsigned short *psSourceData = (unsigned short*)(&(vcSourceData.at(0)));
      for (UINT64 i = 0;i<iDataSize;i++) {
        vTmpHist[psSourceData[size_t(i)]]++;
      }
    } else {
      return false;
    }
  }

  // find maximum-index non zero entry
  size_t iSize = 0;
  for (size_t i = 0;i<iValueRange;i++) if (vTmpHist[i] != 0) iSize = i+1;
  iValueRange = iSize;

  // copy non zero elements in temp histogram to histogram
  m_vHistData.resize(iValueRange);
  if (m_vHistData.size() != iValueRange) return false;
  for (size_t i = 0;i<iValueRange;i++) m_vHistData[i] = vTmpHist[i];

  // set data block information
  strBlockID = "1D Histogram for datablock " + source->strBlockID;

  return true;
}

void Histogram1DDataBlock::CopyHeaderToFile(LargeRAWFile* pStreamFile, UINT64 iOffset, bool bIsBigEndian, bool bIsLastBlock) {
  DataBlock::CopyHeaderToFile(pStreamFile, iOffset, bIsBigEndian, bIsLastBlock);
  UINT64 ulElementCount = UINT64(m_vHistData.size());
  pStreamFile->WriteData(ulElementCount, bIsBigEndian);
}

UINT64 Histogram1DDataBlock::CopyToFile(LargeRAWFile* pStreamFile, UINT64 iOffset, bool bIsBigEndian, bool bIsLastBlock) {
  CopyHeaderToFile(pStreamFile, iOffset, bIsBigEndian, bIsLastBlock);
  pStreamFile->WriteRAW((unsigned char*)&m_vHistData[0], m_vHistData.size()*sizeof(UINT64));
  return pStreamFile->GetPos() - iOffset;
}

UINT64 Histogram1DDataBlock::GetOffsetToNextBlock() const {
  return DataBlock::GetOffsetToNextBlock() + ComputeDataSize();
}

UINT64 Histogram1DDataBlock::ComputeDataSize() const {
  return sizeof(UINT64) +                  // length of the vector
       m_vHistData.size()*sizeof(UINT64);  // the vector itself
}
<commit_msg>formatting.<commit_after>#include "Histogram1DDataBlock.h"

#include "RasterDataBlock.h"
using namespace std;
using namespace UVFTables;

Histogram1DDataBlock::Histogram1DDataBlock() : DataBlock() {
  ulBlockSemantics = BS_1D_HISTOGRAM;
  strBlockID       = "1D Histogram";
}

Histogram1DDataBlock::Histogram1DDataBlock(const Histogram1DDataBlock &other) :
  DataBlock(other),
  m_vHistData(other.m_vHistData)
{
}

Histogram1DDataBlock& Histogram1DDataBlock::operator=(const Histogram1DDataBlock& other) {
  strBlockID = other.strBlockID;
  ulBlockSemantics = other.ulBlockSemantics;
  ulCompressionScheme = other.ulCompressionScheme;
  ulOffsetToNextDataBlock = other.ulOffsetToNextDataBlock;

  m_vHistData = other.m_vHistData;

  return *this;
}

Histogram1DDataBlock::Histogram1DDataBlock(LargeRAWFile* pStreamFile, UINT64 iOffset, bool bIsBigEndian) {
  GetHeaderFromFile(pStreamFile, iOffset, bIsBigEndian);
}

Histogram1DDataBlock::~Histogram1DDataBlock()
{
}

DataBlock* Histogram1DDataBlock::Clone() const {
  return new Histogram1DDataBlock(*this);
}

UINT64 Histogram1DDataBlock::GetHeaderFromFile(LargeRAWFile* pStreamFile, UINT64 iOffset, bool bIsBigEndian) {
  UINT64 iStart = iOffset + DataBlock::GetHeaderFromFile(pStreamFile, iOffset, bIsBigEndian);
  pStreamFile->SeekPos(iStart);

  UINT64 ulElementCount;
  pStreamFile->ReadData(ulElementCount, bIsBigEndian);

  m_vHistData.resize(size_t(ulElementCount));
  pStreamFile->ReadRAW((unsigned char*)&m_vHistData[0], ulElementCount*sizeof(UINT64));
  return pStreamFile->GetPos() - iOffset;
}

bool Histogram1DDataBlock::Compute(const RasterDataBlock* source) {

  // TODO: right now we can only compute Histograms of scalar data this
  // should be changed to a more general approach
  if (source->ulElementDimension != 1 ||
      source->ulElementDimensionSize.size() != 1)
    return false;

  /// \todo right now compute Histogram assumes that at least the
  // lowest LOD level consists only of a single brick, this brick is
  // used for the hist.-computation this should be changed to a more
  // general approach
  vector<UINT64> vSmallestLOD = source->GetSmallestBrickIndex();
  const vector<UINT64>& vBricks = source->GetBrickCount(vSmallestLOD);
  for (size_t i = 0;i<vBricks.size();i++) if (vBricks[i] != 1) return false;

  // create temp histogram
  size_t iValueRange = size_t(1<<(source->ulElementBitSize[0][0]));
  vector<UINT64> vTmpHist(iValueRange, 0);
  if (vTmpHist.size() != iValueRange) return false;

  // LargestSingleBrickLODBrickIndex is well defined as we tested above
  // if we have a single brick LOD
  std::vector<unsigned char> vcSourceData;
  vector<UINT64> vLOD = source->LargestSingleBrickLODBrickIndex();
  vector<UINT64> vOneAndOnly;
  for (size_t i = 0;i<vBricks.size();i++) vOneAndOnly.push_back(0);
  if (!source->GetData(vcSourceData, vLOD, vOneAndOnly)) return false;

  vector<UINT64> vSize  = source->LargestSingleBrickLODBrickSize();

  UINT64 iDataSize = 1;
  for (size_t i = 0;i<vSize.size();i++) iDataSize*=vSize[i];

  /// @todo only 8 and 16 bit integer data are supported.  this should be
  ///       changed to use a more general approach.
  if (source->ulElementBitSize[0][0] == 8) {
    for (UINT64 i = 0;i<iDataSize;i++) {
       vTmpHist[vcSourceData[size_t(i)]]++;
    }
  } else {
    if (source->ulElementBitSize[0][0] == 16) {
      unsigned short *psSourceData = (unsigned short*)(&(vcSourceData.at(0)));
      for (UINT64 i = 0;i<iDataSize;i++) {
        vTmpHist[psSourceData[size_t(i)]]++;
      }
    } else {
      return false;
    }
  }

  // find maximum-index non zero entry
  size_t iSize = 0;
  for (size_t i = 0;i<iValueRange;i++) if (vTmpHist[i] != 0) iSize = i+1;
  iValueRange = iSize;

  // copy non zero elements in temp histogram to histogram
  m_vHistData.resize(iValueRange);
  if (m_vHistData.size() != iValueRange) return false;
  for (size_t i = 0;i<iValueRange;i++) m_vHistData[i] = vTmpHist[i];

  // set data block information
  strBlockID = "1D Histogram for datablock " + source->strBlockID;

  return true;
}

void Histogram1DDataBlock::CopyHeaderToFile(LargeRAWFile* pStreamFile, UINT64 iOffset, bool bIsBigEndian, bool bIsLastBlock) {
  DataBlock::CopyHeaderToFile(pStreamFile, iOffset, bIsBigEndian, bIsLastBlock);
  UINT64 ulElementCount = UINT64(m_vHistData.size());
  pStreamFile->WriteData(ulElementCount, bIsBigEndian);
}

UINT64 Histogram1DDataBlock::CopyToFile(LargeRAWFile* pStreamFile, UINT64 iOffset, bool bIsBigEndian, bool bIsLastBlock) {
  CopyHeaderToFile(pStreamFile, iOffset, bIsBigEndian, bIsLastBlock);
  pStreamFile->WriteRAW((unsigned char*)&m_vHistData[0], m_vHistData.size()*sizeof(UINT64));
  return pStreamFile->GetPos() - iOffset;
}

UINT64 Histogram1DDataBlock::GetOffsetToNextBlock() const {
  return DataBlock::GetOffsetToNextBlock() + ComputeDataSize();
}

UINT64 Histogram1DDataBlock::ComputeDataSize() const {
  return sizeof(UINT64) +                  // length of the vector
       m_vHistData.size()*sizeof(UINT64);  // the vector itself
}
<|endoftext|>


<commit_before>#include <pwd.h>
#include <grp.h>
#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
#include <vector>
#include <sstream>
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
using namespace std;

void printDashL(char* directoryName, vector<string> flags);
bool isDirectory(char* directoryName) {

	struct stat directoryInCurrent;

	if (-1 == (stat(directoryName, &directoryInCurrent))) {

		return false;
	}

	if (directoryInCurrent.st_mode & S_IFDIR) {
		return true;
	}
	else {
		return false;
	}
}

int ls(char* directoryName) {
	if (!isDirectory(directoryName)) {
		cout << directoryName << endl;
		return 1;
	}

		char const *dirName = directoryName;
		DIR *dirp;
		if (!(dirp = opendir(dirName))) {
			cerr << "Error(" << errno << ") opening " << dirName << endl;
		}

		dirent *direntp;
		while ((direntp = readdir(dirp))) {
			if (direntp->d_name[0] != '.') {

				//cout << direntp->d_name << endl; // use stat here to find attributes of a file
				printf(direntp->d_name, 8);
				cout << " ";
			}
		}
		cout << endl;
		closedir(dirp);
		return 0;
}

void printDashL(char* directoryName, vector<string> flags) {

		bool isA = false;
		bool isL = false;
		bool isR = false;
		for (unsigned i = 0; i < flags.size(); ++i) {
			for (unsigned k = 0; k < flags.at(i).size(); ++k) {
				if (flags.at(i).at(k) == 'a')
					isA = true; // there's an -a flag
				else if (flags.at(i).at(k) == 'l')
					isL = true; // there's an -l flag
				else if (flags.at(i).at(k) == 'R')
					isR = true; // there's an -R flag
			}

		}
		struct stat current;
		struct passwd *x;
		struct group *y;
		if (-1 == (stat(directoryName, &current))) {
			perror("stat failed");
			return;
		}
				if (current.st_mode & S_IFDIR)
					cout << "d";

				if (current.st_mode & S_IFLNK)
					cout << "l";

				if (!(current.st_mode & S_IFDIR) && !(current.st_mode & S_IFLNK))
					cout << "-";

				if (current.st_mode & S_IRUSR)
					cout << "r";
				else
					cout << "-";

				if (current.st_mode & S_IWUSR)
					cout << "w";
				else
					cout << "-";

				if (current.st_mode & S_IXUSR)
					cout << "x";
				else
					cout << "-";

				if (current.st_mode & S_IRGRP)
					cout << "r";
				else
					cout << "-";

				if (current.st_mode & S_IWGRP)
					cout << "w";
				else
					cout << "-";

				if (current.st_mode & S_IXGRP)
					cout << "x";
				else
					cout << "-";

				if (current.st_mode & S_IROTH)
					cout << "r";
				else
					cout << "-";

				if (current.st_mode & S_IWOTH)
					cout << "w";
				else
					cout << "-";

				if (current.st_mode & S_IXOTH)
					cout << "x";
				else
					cout << "-";

				cout << " ";

				cout << current.st_nlink << " ";

				if ((x = getpwuid(current.st_uid)) != NULL)
					cout << x->pw_name << " ";
				else {
					cerr << "error: " << errno << endl;
					exit(0);
				}

				if ((y = getgrgid(current.st_gid)) != NULL)
					cout << y->gr_name << " ";
				else {
					cerr << "error: " << errno << endl;
					exit(0);
				}
				cout << current.st_size << " ";

				char buff[20];
				struct tm * timeinfo;
				timeinfo = localtime(&(current.st_mtime));
				strftime(buff, 20, "%b %d %H:%M", timeinfo);
				printf("%s",buff);

				cout << " " << directoryName << endl;
}
int lsWithFlags(char* directoryName, vector<string> flags) {
	if (!isDirectory(directoryName)) {

		bool isA = false;
		bool isL = false;
		bool isR = false;
		for (unsigned i = 0; i < flags.size(); ++i) {
			for (unsigned k = 0; k < flags.at(i).size(); ++k) {
				if (flags.at(i).at(k) == 'a')
					isA = true; // there's an -a flag
				else if (flags.at(i).at(k) == 'l')
					isL = true; // there's an -l flag
				else if (flags.at(i).at(k) == 'R')
					isR = true; // there's an -R flag
			}

		}
		if (isL) {
			printDashL(directoryName, flags);
		}
		else {
			cout << directoryName << endl;
		}
		return 1;

	}

	char const *dirName = directoryName;
	DIR *dirp;
	if (!(dirp = opendir(dirName))) {
		cerr << "Error(" << errno << ") opening " << dirName << endl;
		return errno;
	}

	bool isA = false;
	bool isL = false;
	bool isR = false;
	for (unsigned i = 0; i < flags.size(); ++i) {
		for (unsigned k = 0; k < flags.at(i).size(); ++k) {
			if (flags.at(i).at(k) == 'a')
				isA = true; // there's an -a flag
			else if (flags.at(i).at(k) == 'l')
				isL = true; // there's an -l flag
			else if (flags.at(i).at(k) == 'R')
				isR = true; // there's an -R flag
		}

	}

	dirent *direntp;

	if (isR && isDirectory(directoryName)) {
		vector<char*> dirsInCurdir;
		int i = 0;
		while ((direntp = readdir(dirp))) {
			string temp = directoryName;
			temp.append("/");
			temp.append(direntp->d_name);
			char *x;
			x = new char[temp.size() + 1];
			strcpy(x, temp.c_str());
			dirsInCurdir.push_back(x);
			++i;
		}

		for (int j = 0; j < i; ++i) {
			cout << *dirsInCurdir[j] << ":\n";
			return lsWithFlags(dirsInCurdir[j], flags);
			cout << endl;
		for (int j = 0; j < i; ++j)
			delete [] dirsInCurdir[j];
	}

	if (!isL && !isA)
		return ls(directoryName);

	if (isL) { //run -l flag

		struct stat current;

		struct passwd *x;
		struct group *y;
		while ((direntp = readdir(dirp))) {
			string temp = directoryName;
			temp.append("/");
			temp.append(direntp->d_name);
			//cout << "direntp: " << direntp->d_name << endl;
			char* curdir = new char[temp.size() + 1];
			strcpy(curdir, temp.c_str());

			//cout << curdir << endl;
			if (-1 == (stat(curdir, &current))) {

				perror("stat failed");
				return -1;
			}
			if (direntp->d_name[0] == '.' && !isA)	{ // if there's no -a flag, don't print files
															   // starting with .
				continue;
			}
			else {

				if (current.st_mode & S_IFDIR)
					cout << "d";

				if (current.st_mode & S_IFLNK)
					cout << "l";

				if (!(current.st_mode & S_IFDIR) && !(current.st_mode & S_IFLNK))
					cout << "-";

				if (current.st_mode & S_IRUSR)
					cout << "r";
				else
					cout << "-";

				if (current.st_mode & S_IWUSR)
					cout << "w";
				else
					cout << "-";

				if (current.st_mode & S_IXUSR)
					cout << "x";
				else
					cout << "-";

				if (current.st_mode & S_IRGRP)
					cout << "r";
				else
					cout << "-";

				if (current.st_mode & S_IWGRP)
					cout << "w";
				else
					cout << "-";

				if (current.st_mode & S_IXGRP)
					cout << "x";
				else
					cout << "-";

				if (current.st_mode & S_IROTH)
					cout << "r";
				else
					cout << "-";

				if (current.st_mode & S_IWOTH)
					cout << "w";
				else
					cout << "-";

				if (current.st_mode & S_IXOTH)
					cout << "x";
				else
					cout << "-";

				cout << " ";

				cout << current.st_nlink << " ";

				if ((x = getpwuid(current.st_uid)) != NULL)
					cout << x->pw_name << " ";
				else {
					cerr << "error: " << errno << endl;
					exit(0);
				}

				if ((y = getgrgid(current.st_gid)) != NULL)
					cout << y->gr_name << " ";
				else {
					cerr << "error: " << errno << endl;
					exit(0);
				}
				cout << current.st_size << " ";

				char buff[20];
				struct tm * timeinfo;
				timeinfo = localtime(&(current.st_mtime));
				strftime(buff, 20, "%b %d %H:%M", timeinfo);
				printf("%s",buff);

				cout << " " << direntp->d_name;
			}
			cout << endl;
			delete [] curdir;

		}
		closedir(dirp);

	}

	else if (isA) {
		while ((direntp = readdir(dirp))) {

			//cout << direntp->d_name << endl; // use stat here to find attributes of a file
			printf(direntp->d_name, 8);
			cout << " ";

		}
		if (-1 == (closedir(dirp))) {
			perror("closedir failed");
		}
		cout << endl;
	}
	return 0;
}

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

	if (argc == 1) {

		if (errno == ls(".")) {

			return errno;
		}
	}

	else {

		vector<string> directories;
		vector<string> flags;
		string toInsert = "./";
		for (int i = 1; i < argc; ++i) {

			if (argv[i][0] == '-') {

				flags.push_back(argv[i]);
			} else {

				directories.push_back(argv[i]);
			}
		}

		for (unsigned i = 0; i < directories.size(); ++i) {

			directories.at(i).insert(0, toInsert);
		}
		if (flags.size() == 0) {

			for (unsigned i = 0; i < directories.size(); ++i) {

				char* directoryName = new char[directories.at(i).size() + 1];
				strcpy(directoryName, directories.at(i).c_str());

				ls(directoryName);

				delete [] directoryName;
			}
		}
		else if (directories.size() == 0) {

			lsWithFlags(".", flags);
		}
		else {
			//cout << "directories: ";
			//for (unsigned i = 0; i < directories.size(); ++i)
				//cout << directories.at(i) << " ";
			//cout << endl;

			if (directories.size() == 1) {

				char* directoryName = new char[directories.at(0).size() + 1];
				strcpy(directoryName, directories.at(0).c_str());

				lsWithFlags(directoryName, flags);

				delete [] directoryName;
			}

			else {
				for (unsigned int i = 0; i < directories.size(); ++i) {
					//cout << 145 << endl;

					char* directoryName = new char[directories.at(i).size() + 1];
					strcpy(directoryName, directories.at(i).c_str());
					cout << directoryName << ":" << endl;
					lsWithFlags(directoryName, flags);
					delete [] directoryName;
					cout << endl;
				}
			}
		}
	}

}

<commit_msg>added -l protection functionality<commit_after>#include <pwd.h>
#include <grp.h>
#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
#include <vector>
#include <sstream>
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
using namespace std;

void printDashL(char* directoryName, vector<string> flags);
bool isDirectory(char* directoryName) {

	struct stat directoryInCurrent;

	if (-1 == (stat(directoryName, &directoryInCurrent))) {

		return false;
	}

	if (directoryInCurrent.st_mode & S_IFDIR) {
		return true;
	}
	else {
		return false;
	}
}

int ls(char* directoryName) {
	if (!isDirectory(directoryName)) {
		cout << directoryName << endl;
		return 1;
	}

		char const *dirName = directoryName;
		DIR *dirp;
		if (!(dirp = opendir(dirName))) {
			cerr << "Error(" << errno << ") opening " << dirName << endl;
		}

		dirent *direntp;
		while ((direntp = readdir(dirp))) {
			if (direntp->d_name[0] != '.') {

				//cout << direntp->d_name << endl; // use stat here to find attributes of a file
				printf(direntp->d_name, 8);
				cout << " ";
			}
		}
		cout << endl;
		closedir(dirp);
		return 0;
}

void printDashL(char* directoryName, vector<string> flags) {

		bool isA = false;
		bool isL = false;
		bool isR = false;
		for (unsigned i = 0; i < flags.size(); ++i) {
			for (unsigned k = 0; k < flags.at(i).size(); ++k) {
				if (flags.at(i).at(k) == 'a')
					isA = true; // there's an -a flag
				else if (flags.at(i).at(k) == 'l')
					isL = true; // there's an -l flag
				else if (flags.at(i).at(k) == 'R')
					isR = true; // there's an -R flag
			}

		}
		struct stat current;
		struct passwd *x;
		struct group *y;
		if (-1 == (stat(directoryName, &current))) {
			perror("stat failed");
			return;
		}
				if (current.st_mode & S_IFDIR)
					cout << "d";

				if (current.st_mode & S_IFLNK)
					cout << "l";

				if (!(current.st_mode & S_IFDIR) && !(current.st_mode & S_IFLNK))
					cout << "-";

				if (current.st_mode & S_IRUSR)
					cout << "r";
				else
					cout << "-";

				if (current.st_mode & S_IWUSR)
					cout << "w";
				else
					cout << "-";

				if (current.st_mode & S_IXUSR)
					cout << "x";
				else
					cout << "-";

				if (current.st_mode & S_IRGRP)
					cout << "r";
				else
					cout << "-";

				if (current.st_mode & S_IWGRP)
					cout << "w";
				else
					cout << "-";

				if (current.st_mode & S_IXGRP)
					cout << "x";
				else
					cout << "-";

				if (current.st_mode & S_IROTH)
					cout << "r";
				else
					cout << "-";

				if (current.st_mode & S_IWOTH)
					cout << "w";
				else
					cout << "-";

				if (current.st_mode & S_IXOTH)
					cout << "x";
				else
					cout << "-";

				cout << " ";

				cout << current.st_nlink << " ";

				if ((x = getpwuid(current.st_uid)) != NULL)
					cout << x->pw_name << " ";
				else {
					cerr << "error: " << errno << endl;
					exit(0);
				}

				if ((y = getgrgid(current.st_gid)) != NULL)
					cout << y->gr_name << " ";
				else {
					cerr << "error: " << errno << endl;
					exit(0);
				}
				cout << current.st_size << " ";

				char buff[20];
				struct tm * timeinfo;
				timeinfo = localtime(&(current.st_mtime));
				strftime(buff, 20, "%b %d %H:%M", timeinfo);
				printf("%s",buff);

				cout << " " << directoryName << endl;
}
int lsWithFlags(char* directoryName, vector<string> flags) {
	if (!isDirectory(directoryName)) {

		bool isA = false;
		bool isL = false;
		bool isR = false;
		for (unsigned i = 0; i < flags.size(); ++i) {
			for (unsigned k = 0; k < flags.at(i).size(); ++k) {
				if (flags.at(i).at(k) == 'a')
					isA = true; // there's an -a flag
				else if (flags.at(i).at(k) == 'l')
					isL = true; // there's an -l flag
				else if (flags.at(i).at(k) == 'R')
					isR = true; // there's an -R flag
			}

		}
		if (isL) {
			printDashL(directoryName, flags);
		}
		else {
			cout << directoryName << endl;
		}
		return 1;

	}

	char const *dirName = directoryName;
	DIR *dirp;
	if (!(dirp = opendir(dirName))) {
		cerr << "Error(" << errno << ") opening " << dirName << endl;
		return errno;
	}

	bool isA = false;
	bool isL = false;
	bool isR = false;
	for (unsigned i = 0; i < flags.size(); ++i) {
		for (unsigned k = 0; k < flags.at(i).size(); ++k) {
			if (flags.at(i).at(k) == 'a')
				isA = true; // there's an -a flag
			else if (flags.at(i).at(k) == 'l')
				isL = true; // there's an -l flag
			else if (flags.at(i).at(k) == 'R')
				isR = true; // there's an -R flag
		}

	}

	dirent *direntp;

	if (isR && isDirectory(directoryName)) {
		vector<char*> dirsInCurdir;
		int i = 0;
		while ((direntp = readdir(dirp))) {
			string temp = directoryName;
			temp.append("/");
			temp.append(direntp->d_name);
			char *x;
			x = new char[temp.size() + 1];
			strcpy(x, temp.c_str());
			dirsInCurdir.push_back(x);
			++i;
		}

		for (int j = 0; j < i; ++i) {
			cout << *dirsInCurdir[j] << ":\n";
			return lsWithFlags(dirsInCurdir[j], flags);
			cout << endl;
		}
		for (int j = 0; j < i; ++j)
			delete [] dirsInCurdir[j];
	}

	if (!isL && !isA)
		return ls(directoryName);

	if (isL) { //run -l flag

		struct stat current;

		struct passwd *x;
		struct group *y;
		while ((direntp = readdir(dirp))) {
			string temp = directoryName;
			temp.append("/");
			temp.append(direntp->d_name);
			//cout << "direntp: " << direntp->d_name << endl;
			char* curdir = new char[temp.size() + 1];
			strcpy(curdir, temp.c_str());

			//cout << curdir << endl;
			if (-1 == (stat(curdir, &current))) {

				perror("stat failed");
				return -1;
			}
			if (direntp->d_name[0] == '.' && !isA)	{ // if there's no -a flag, don't print files
															   // starting with .
				continue;
			}
			else {

				if (current.st_mode & S_IFDIR)
					cout << "d";

				if (current.st_mode & S_IFLNK)
					cout << "l";

				if (!(current.st_mode & S_IFDIR) && !(current.st_mode & S_IFLNK))
					cout << "-";

				if (current.st_mode & S_IRUSR)
					cout << "r";
				else
					cout << "-";

				if (current.st_mode & S_IWUSR)
					cout << "w";
				else
					cout << "-";

				if (current.st_mode & S_IXUSR)
					cout << "x";
				else
					cout << "-";

				if (current.st_mode & S_IRGRP)
					cout << "r";
				else
					cout << "-";

				if (current.st_mode & S_IWGRP)
					cout << "w";
				else
					cout << "-";

				if (current.st_mode & S_IXGRP)
					cout << "x";
				else
					cout << "-";

				if (current.st_mode & S_IROTH)
					cout << "r";
				else
					cout << "-";

				if (current.st_mode & S_IWOTH)
					cout << "w";
				else
					cout << "-";

				if (current.st_mode & S_IXOTH)
					cout << "x";
				else
					cout << "-";

				cout << " ";

				cout << current.st_nlink << " ";

				if ((x = getpwuid(current.st_uid)) != NULL)
					cout << x->pw_name << " ";
				else {
					cerr << "error: " << errno << endl;
					exit(0);
				}

				if ((y = getgrgid(current.st_gid)) != NULL)
					cout << y->gr_name << " ";
				else {
					cerr << "error: " << errno << endl;
					exit(0);
				}
				cout << current.st_size << " ";

				char buff[20];
				struct tm * timeinfo;
				timeinfo = localtime(&(current.st_mtime));
				strftime(buff, 20, "%b %d %H:%M", timeinfo);
				printf("%s",buff);

				cout << " " << direntp->d_name;
			}
			cout << endl;
			delete [] curdir;

		}
		closedir(dirp);

	}

	else if (isA) {
		while ((direntp = readdir(dirp))) {

			//cout << direntp->d_name << endl; // use stat here to find attributes of a file
			printf(direntp->d_name, 8);
			cout << " ";

		}
		if (-1 == (closedir(dirp))) {
			perror("closedir failed");
		}
		cout << endl;
	}
	return 0;
}

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

	if (argc == 1) {

		if (errno == ls(".")) {

			return errno;
		}
	}

	else {

		vector<string> directories;
		vector<string> flags;
		string toInsert = "./";
		for (int i = 1; i < argc; ++i) {

			if (argv[i][0] == '-') {

				flags.push_back(argv[i]);
			} else {

				directories.push_back(argv[i]);
			}
		}

		for (unsigned i = 0; i < directories.size(); ++i) {

			directories.at(i).insert(0, toInsert);
		}
		if (flags.size() == 0) {

			for (unsigned i = 0; i < directories.size(); ++i) {

				char* directoryName = new char[directories.at(i).size() + 1];
				strcpy(directoryName, directories.at(i).c_str());

				ls(directoryName);

				delete [] directoryName;
			}
		}
		else if (directories.size() == 0) {

			lsWithFlags(".", flags);
		}
		else {
			//cout << "directories: ";
			//for (unsigned i = 0; i < directories.size(); ++i)
				//cout << directories.at(i) << " ";
			//cout << endl;

			if (directories.size() == 1) {

				char* directoryName = new char[directories.at(0).size() + 1];
				strcpy(directoryName, directories.at(0).c_str());

				lsWithFlags(directoryName, flags);

				delete [] directoryName;
			}

			else {
				for (unsigned int i = 0; i < directories.size(); ++i) {
					//cout << 145 << endl;

					char* directoryName = new char[directories.at(i).size() + 1];
					strcpy(directoryName, directories.at(i).c_str());
					cout << directoryName << ":" << endl;
					lsWithFlags(directoryName, flags);
					delete [] directoryName;
					cout << endl;
				}
			}
		}
	}

}

<|endoftext|>


<commit_before>#include <UnitTest/stdafx.h>
#include <UnitTest/UnitTest.h>
#include <core/addin/addin.h>
#include <core/addin/mfcmapi.h>

namespace addin
{
	// imports for testing
	int _cdecl compareTypes(_In_ const void* a1, _In_ const void* a2) noexcept;
	int _cdecl compareTags(_In_ const void* a1, _In_ const void* a2) noexcept;
	int _cdecl compareNameID(_In_ const void* a1, _In_ const void* a2) noexcept;
	int _cdecl compareSmartViewParser(_In_ const void* a1, _In_ const void* a2) noexcept;

	void SortFlagArray(_In_count_(ulFlags) LPFLAG_ARRAY_ENTRY lpFlags, _In_ size_t ulFlags) noexcept;
	void AppendFlagIfNotDupe(std::vector<FLAG_ARRAY_ENTRY>& target, FLAG_ARRAY_ENTRY source);

	void MergeFlagArrays(std::vector<FLAG_ARRAY_ENTRY>& In1, _In_count_(cIn2) LPFLAG_ARRAY_ENTRY In2, _In_ size_t cIn2);
} // namespace addin

namespace addintest
{
	int _cdecl testCompareTypes(_In_ const NAME_ARRAY_ENTRY& a1, _In_ const NAME_ARRAY_ENTRY& a2) noexcept
	{
		return addin::compareTypes(reinterpret_cast<LPCVOID>(&a1), reinterpret_cast<LPCVOID>(&a2));
	}

	int _cdecl testCompareTags(_In_ const NAME_ARRAY_ENTRY_V2& a1, _In_ const NAME_ARRAY_ENTRY_V2& a2) noexcept
	{
		return addin::compareTags(reinterpret_cast<LPCVOID>(&a1), reinterpret_cast<LPCVOID>(&a2));
	}

	int _cdecl testCompareNameID(_In_ const NAMEID_ARRAY_ENTRY& a1, _In_ const NAMEID_ARRAY_ENTRY& a2) noexcept
	{
		return addin::compareNameID(reinterpret_cast<LPCVOID>(&a1), reinterpret_cast<LPCVOID>(&a2));
	}

	int _cdecl testCompareSmartViewParser(
		_In_ const SMARTVIEW_PARSER_ARRAY_ENTRY& a1,
		_In_ const SMARTVIEW_PARSER_ARRAY_ENTRY& a2) noexcept
	{
		return addin::compareSmartViewParser(reinterpret_cast<LPCVOID>(&a1), reinterpret_cast<LPCVOID>(&a2));
	}

	TEST_CLASS(addinTest)
	{
	public:
		// Without this, clang gets weird
		static const bool dummy_var = true;

		TEST_CLASS_INITIALIZE(initialize) { unittest::init(); }

		TEST_METHOD(Test_compareTypes)
		{
			Assert::AreEqual(0, testCompareTypes({1, L"one"}, {1, L"one"}));
			Assert::AreEqual(-1, testCompareTypes({1, L"one"}, {2, L"two"}));
			Assert::AreEqual(1, testCompareTypes({2, L"two"}, {1, L"one"}));

			Assert::AreEqual(-1, testCompareTypes({1, L"a"}, {1, L"b"}));
			Assert::AreEqual(1, testCompareTypes({1, L"b"}, {1, L"a"}));

			// Same name gets no special treatment
			Assert::AreEqual(-1, testCompareTypes({1, L"one"}, {2, L"one"}));
			Assert::AreEqual(1, testCompareTypes({2, L"one"}, {1, L"one"}));
		}

		TEST_METHOD(Test_compareTags)
		{
			Assert::AreEqual(0, testCompareTags({1, 0, L"one"}, {1, 0, L"one"}));
			Assert::AreEqual(-1, testCompareTags({1, 0, L"one"}, {2, 0, L"two"}));
			Assert::AreEqual(1, testCompareTags({2, 0, L"two"}, {1, 0, L"one"}));

			Assert::AreEqual(-1, testCompareTags({1, 0, L"a"}, {1, 0, L"b"}));
			Assert::AreEqual(-1, testCompareTags({1, 0, L"a"}, {1, 1, L"b"}));

			// Sort order field doesn't actually affect this particular sort
			Assert::AreEqual(-1, testCompareTags({1, 1, L"a"}, {1, 0, L"b"}));
			Assert::AreEqual(1, testCompareTags({1, 0, L"b"}, {1, 0, L"a"}));

			// Same name compares equal
			Assert::AreEqual(0, testCompareTags({1, 0, L"one"}, {2, 0, L"one"}));
		}

		TEST_METHOD(Test_compareNameID)
		{
			Assert::AreEqual(
				0,
				testCompareNameID(
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"},
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"}));
			Assert::AreEqual(
				-1,
				testCompareNameID(
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"},
					{2, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"}));
			Assert::AreEqual(
				1,
				testCompareNameID(
					{2, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"},
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"}));
			Assert::AreEqual(
				-1,
				testCompareNameID(
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"},
					{1, &guid::PSETID_Note, L"a", PT_SYSTIME, L"aa"}));
			Assert::AreEqual(
				-1,
				testCompareNameID(
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"},
					{1, &guid::PSETID_Meeting, L"b", PT_SYSTIME, L"bb"}));
			Assert::AreEqual(
				1,
				testCompareNameID(
					{1, &guid::PSETID_Meeting, L"b", PT_SYSTIME, L"bb"},
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"}));
		}

		TEST_METHOD(Test_CompareSmartViewParser)
		{
			Assert::AreEqual(
				0, testCompareSmartViewParser({1, parserType::REPORTTAG, false}, {1, parserType::REPORTTAG, false}));
			Assert::AreEqual(
				-1, testCompareSmartViewParser({1, parserType::REPORTTAG, false}, {2, parserType::REPORTTAG, false}));
			Assert::AreEqual(
				1, testCompareSmartViewParser({2, parserType::REPORTTAG, false}, {1, parserType::REPORTTAG, false}));

			Assert::AreEqual(
				-1, testCompareSmartViewParser({1, parserType::ENTRYID, false}, {1, parserType::REPORTTAG, false}));
			Assert::AreEqual(
				1, testCompareSmartViewParser({1, parserType::REPORTTAG, false}, {1, parserType::ENTRYID, false}));

			Assert::AreEqual(
				-1, testCompareSmartViewParser({1, parserType::REPORTTAG, false}, {1, parserType::REPORTTAG, true}));
			Assert::AreEqual(
				1, testCompareSmartViewParser({1, parserType::REPORTTAG, true}, {1, parserType::REPORTTAG, false}));
		}

		void testFA(std::wstring testName, const FLAG_ARRAY_ENTRY& fa1, const FLAG_ARRAY_ENTRY& fa2)
		{
			Assert::AreEqual(fa1.ulFlagName, fa2.ulFlagName, (testName + L"-ulFlagName").c_str());
			Assert::AreEqual(fa1.lFlagValue, fa2.lFlagValue, (testName + L"-lFlagValue").c_str());
			Assert::AreEqual(fa1.ulFlagType, fa2.ulFlagType, (testName + L"-ulFlagType").c_str());
			Assert::AreEqual(fa1.lpszName, fa2.lpszName, (testName + L"-lpszName").c_str());
		}

		TEST_METHOD(Test_FlagArray)
		{
			FLAG_ARRAY_ENTRY flagArray[] = {
				{2, 1, flagVALUE, L"b one"},
				{1, 2, flagVALUE, L"two"},
				{2, 3, flagVALUE, L"a three"},
				{1, 1, flagVALUE, L"one"},
			};

			// Do a stable sort on ulFlagName (first member)
			addin::SortFlagArray(flagArray, _countof(flagArray));

			testFA(L"0", flagArray[0], {1, 2, flagVALUE, L"two"});
			testFA(L"1", flagArray[1], {1, 1, flagVALUE, L"one"});
			testFA(L"2", flagArray[2], {2, 1, flagVALUE, L"b one"});
			testFA(L"3", flagArray[3], {2, 3, flagVALUE, L"a three"});

			auto flagV = std::vector<FLAG_ARRAY_ENTRY>{};
			addin::AppendFlagIfNotDupe(flagV, {1, 3, flagVALUE, L"three"});
			testFA(L"add 1", flagV[0], {1, 3, flagVALUE, L"three"});

			addin::AppendFlagIfNotDupe(flagV, {1, 4, flagVALUE, L"one"});
			testFA(L"add 2", flagV[1], {1, 4, flagVALUE, L"one"});
			addin::AppendFlagIfNotDupe(flagV, {1, 4, flagVALUE, L"one"});
			Assert::AreEqual(size_t{2}, flagV.size(), L"no dupe");

			addin::AppendFlagIfNotDupe(flagV, {2, 2, flagVALUE, L"c two"});
			testFA(L"add 3", flagV[2], {2, 2, flagVALUE, L"c two"});

			addin::MergeFlagArrays(flagV, flagArray, _countof(flagArray));
			Assert::AreEqual(size_t{7}, flagV.size(), L"merge size");

			testFA(L"m0", flagV[0], {1, 3, flagVALUE, L"three"});
			testFA(L"m1", flagV[1], {1, 4, flagVALUE, L"one"});
			testFA(L"m2", flagV[2], {1, 2, flagVALUE, L"two"});
			testFA(L"m3", flagV[3], {1, 1, flagVALUE, L"one"});
			testFA(L"m4", flagV[4], {2, 2, flagVALUE, L"c two"});
			testFA(L"m5", flagV[5], {2, 1, flagVALUE, L"b one"});
			testFA(L"m6", flagV[6], {2, 3, flagVALUE, L"a three"});

			auto flagV2 = std::vector<FLAG_ARRAY_ENTRY>{};
			addin::AppendFlagIfNotDupe(flagV2, {4, 3, flagVALUE, L"three"});
			testFA(L"f2 add 1", flagV2[0], {4, 3, flagVALUE, L"three"});
			addin::MergeFlagArrays(flagV2, nullptr, 0);
			Assert::AreEqual(size_t{1}, flagV2.size(), L"merge null");

			addin::AppendFlagIfNotDupe(flagV2, {4, 4, flagVALUE, L"four"});
			Assert::AreEqual(size_t{2}, flagV2.size(), L"merge null");
			testFA(L"f2 add 2", flagV2[1], {4, 4, flagVALUE, L"four"});

			FLAG_ARRAY_ENTRY flagArray2[] = {{3, 1, flagVALUE, L"four one"}};
			addin::MergeFlagArrays(flagV2, flagArray2, _countof(flagArray2));
			Assert::AreEqual(size_t{3}, flagV2.size(), L"merge null");
			testFA(L"f2 merge", flagV2[0], {3, 1, flagVALUE, L"four one"});
		}
	};
} // namespace addintest<commit_msg>add another test<commit_after>#include <UnitTest/stdafx.h>
#include <UnitTest/UnitTest.h>
#include <core/addin/addin.h>
#include <core/addin/mfcmapi.h>

namespace addin
{
	// imports for testing
	int _cdecl compareTypes(_In_ const void* a1, _In_ const void* a2) noexcept;
	int _cdecl compareTags(_In_ const void* a1, _In_ const void* a2) noexcept;
	int _cdecl compareNameID(_In_ const void* a1, _In_ const void* a2) noexcept;
	int _cdecl compareSmartViewParser(_In_ const void* a1, _In_ const void* a2) noexcept;

	std::wstring AddInStructTypeToString(parserType parser);

	void SortFlagArray(_In_count_(ulFlags) LPFLAG_ARRAY_ENTRY lpFlags, _In_ size_t ulFlags) noexcept;
	void AppendFlagIfNotDupe(std::vector<FLAG_ARRAY_ENTRY>& target, FLAG_ARRAY_ENTRY source);

	void MergeFlagArrays(std::vector<FLAG_ARRAY_ENTRY>& In1, _In_count_(cIn2) LPFLAG_ARRAY_ENTRY In2, _In_ size_t cIn2);
} // namespace addin

namespace addintest
{
	int _cdecl testCompareTypes(_In_ const NAME_ARRAY_ENTRY& a1, _In_ const NAME_ARRAY_ENTRY& a2) noexcept
	{
		return addin::compareTypes(reinterpret_cast<LPCVOID>(&a1), reinterpret_cast<LPCVOID>(&a2));
	}

	int _cdecl testCompareTags(_In_ const NAME_ARRAY_ENTRY_V2& a1, _In_ const NAME_ARRAY_ENTRY_V2& a2) noexcept
	{
		return addin::compareTags(reinterpret_cast<LPCVOID>(&a1), reinterpret_cast<LPCVOID>(&a2));
	}

	int _cdecl testCompareNameID(_In_ const NAMEID_ARRAY_ENTRY& a1, _In_ const NAMEID_ARRAY_ENTRY& a2) noexcept
	{
		return addin::compareNameID(reinterpret_cast<LPCVOID>(&a1), reinterpret_cast<LPCVOID>(&a2));
	}

	int _cdecl testCompareSmartViewParser(
		_In_ const SMARTVIEW_PARSER_ARRAY_ENTRY& a1,
		_In_ const SMARTVIEW_PARSER_ARRAY_ENTRY& a2) noexcept
	{
		return addin::compareSmartViewParser(reinterpret_cast<LPCVOID>(&a1), reinterpret_cast<LPCVOID>(&a2));
	}

	TEST_CLASS(addinTest)
	{
	public:
		// Without this, clang gets weird
		static const bool dummy_var = true;

		TEST_CLASS_INITIALIZE(initialize) { unittest::init(); }

		TEST_METHOD(Test_compareTypes)
		{
			Assert::AreEqual(0, testCompareTypes({1, L"one"}, {1, L"one"}));
			Assert::AreEqual(-1, testCompareTypes({1, L"one"}, {2, L"two"}));
			Assert::AreEqual(1, testCompareTypes({2, L"two"}, {1, L"one"}));

			Assert::AreEqual(-1, testCompareTypes({1, L"a"}, {1, L"b"}));
			Assert::AreEqual(1, testCompareTypes({1, L"b"}, {1, L"a"}));

			// Same name gets no special treatment
			Assert::AreEqual(-1, testCompareTypes({1, L"one"}, {2, L"one"}));
			Assert::AreEqual(1, testCompareTypes({2, L"one"}, {1, L"one"}));
		}

		TEST_METHOD(Test_compareTags)
		{
			Assert::AreEqual(0, testCompareTags({1, 0, L"one"}, {1, 0, L"one"}));
			Assert::AreEqual(-1, testCompareTags({1, 0, L"one"}, {2, 0, L"two"}));
			Assert::AreEqual(1, testCompareTags({2, 0, L"two"}, {1, 0, L"one"}));

			Assert::AreEqual(-1, testCompareTags({1, 0, L"a"}, {1, 0, L"b"}));
			Assert::AreEqual(-1, testCompareTags({1, 0, L"a"}, {1, 1, L"b"}));

			// Sort order field doesn't actually affect this particular sort
			Assert::AreEqual(-1, testCompareTags({1, 1, L"a"}, {1, 0, L"b"}));
			Assert::AreEqual(1, testCompareTags({1, 0, L"b"}, {1, 0, L"a"}));

			// Same name compares equal
			Assert::AreEqual(0, testCompareTags({1, 0, L"one"}, {2, 0, L"one"}));
		}

		TEST_METHOD(Test_compareNameID)
		{
			Assert::AreEqual(
				0,
				testCompareNameID(
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"},
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"}));
			Assert::AreEqual(
				-1,
				testCompareNameID(
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"},
					{2, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"}));
			Assert::AreEqual(
				1,
				testCompareNameID(
					{2, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"},
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"}));
			Assert::AreEqual(
				-1,
				testCompareNameID(
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"},
					{1, &guid::PSETID_Note, L"a", PT_SYSTIME, L"aa"}));
			Assert::AreEqual(
				-1,
				testCompareNameID(
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"},
					{1, &guid::PSETID_Meeting, L"b", PT_SYSTIME, L"bb"}));
			Assert::AreEqual(
				1,
				testCompareNameID(
					{1, &guid::PSETID_Meeting, L"b", PT_SYSTIME, L"bb"},
					{1, &guid::PSETID_Meeting, L"a", PT_SYSTIME, L"aa"}));
		}

		TEST_METHOD(Test_CompareSmartViewParser)
		{
			Assert::AreEqual(
				0, testCompareSmartViewParser({1, parserType::REPORTTAG, false}, {1, parserType::REPORTTAG, false}));
			Assert::AreEqual(
				-1, testCompareSmartViewParser({1, parserType::REPORTTAG, false}, {2, parserType::REPORTTAG, false}));
			Assert::AreEqual(
				1, testCompareSmartViewParser({2, parserType::REPORTTAG, false}, {1, parserType::REPORTTAG, false}));

			Assert::AreEqual(
				-1, testCompareSmartViewParser({1, parserType::ENTRYID, false}, {1, parserType::REPORTTAG, false}));
			Assert::AreEqual(
				1, testCompareSmartViewParser({1, parserType::REPORTTAG, false}, {1, parserType::ENTRYID, false}));

			Assert::AreEqual(
				-1, testCompareSmartViewParser({1, parserType::REPORTTAG, false}, {1, parserType::REPORTTAG, true}));
			Assert::AreEqual(
				1, testCompareSmartViewParser({1, parserType::REPORTTAG, true}, {1, parserType::REPORTTAG, false}));
		}

		//AddInStructTypeToString
		TEST_METHOD(Test_AddInStructTypeToString)
		{
			Assert::AreEqual(
				L"Choose Smart View Parser",
				addin::AddInStructTypeToString(parserType::NOPARSING).c_str(),
				L"NOPARSING");
			Assert::AreEqual(L"", addin::AddInStructTypeToString(parserType{0xfff}).c_str(), L"unknown");
		}

		void testFA(std::wstring testName, const FLAG_ARRAY_ENTRY& fa1, const FLAG_ARRAY_ENTRY& fa2)
		{
			Assert::AreEqual(fa1.ulFlagName, fa2.ulFlagName, (testName + L"-ulFlagName").c_str());
			Assert::AreEqual(fa1.lFlagValue, fa2.lFlagValue, (testName + L"-lFlagValue").c_str());
			Assert::AreEqual(fa1.ulFlagType, fa2.ulFlagType, (testName + L"-ulFlagType").c_str());
			Assert::AreEqual(fa1.lpszName, fa2.lpszName, (testName + L"-lpszName").c_str());
		}

		TEST_METHOD(Test_FlagArray)
		{
			FLAG_ARRAY_ENTRY flagArray[] = {
				{2, 1, flagVALUE, L"b one"},
				{1, 2, flagVALUE, L"two"},
				{2, 3, flagVALUE, L"a three"},
				{1, 1, flagVALUE, L"one"},
			};

			// Do a stable sort on ulFlagName (first member)
			addin::SortFlagArray(flagArray, _countof(flagArray));

			testFA(L"0", flagArray[0], {1, 2, flagVALUE, L"two"});
			testFA(L"1", flagArray[1], {1, 1, flagVALUE, L"one"});
			testFA(L"2", flagArray[2], {2, 1, flagVALUE, L"b one"});
			testFA(L"3", flagArray[3], {2, 3, flagVALUE, L"a three"});

			auto flagV = std::vector<FLAG_ARRAY_ENTRY>{};
			addin::AppendFlagIfNotDupe(flagV, {1, 3, flagVALUE, L"three"});
			testFA(L"add 1", flagV[0], {1, 3, flagVALUE, L"three"});

			addin::AppendFlagIfNotDupe(flagV, {1, 4, flagVALUE, L"one"});
			testFA(L"add 2", flagV[1], {1, 4, flagVALUE, L"one"});
			addin::AppendFlagIfNotDupe(flagV, {1, 4, flagVALUE, L"one"});
			Assert::AreEqual(size_t{2}, flagV.size(), L"no dupe");

			addin::AppendFlagIfNotDupe(flagV, {2, 2, flagVALUE, L"c two"});
			testFA(L"add 3", flagV[2], {2, 2, flagVALUE, L"c two"});

			addin::MergeFlagArrays(flagV, flagArray, _countof(flagArray));
			Assert::AreEqual(size_t{7}, flagV.size(), L"merge size");

			testFA(L"m0", flagV[0], {1, 3, flagVALUE, L"three"});
			testFA(L"m1", flagV[1], {1, 4, flagVALUE, L"one"});
			testFA(L"m2", flagV[2], {1, 2, flagVALUE, L"two"});
			testFA(L"m3", flagV[3], {1, 1, flagVALUE, L"one"});
			testFA(L"m4", flagV[4], {2, 2, flagVALUE, L"c two"});
			testFA(L"m5", flagV[5], {2, 1, flagVALUE, L"b one"});
			testFA(L"m6", flagV[6], {2, 3, flagVALUE, L"a three"});

			auto flagV2 = std::vector<FLAG_ARRAY_ENTRY>{};
			addin::AppendFlagIfNotDupe(flagV2, {4, 3, flagVALUE, L"three"});
			testFA(L"f2 add 1", flagV2[0], {4, 3, flagVALUE, L"three"});
			addin::MergeFlagArrays(flagV2, nullptr, 0);
			Assert::AreEqual(size_t{1}, flagV2.size(), L"merge null");

			addin::AppendFlagIfNotDupe(flagV2, {4, 4, flagVALUE, L"four"});
			Assert::AreEqual(size_t{2}, flagV2.size(), L"merge null");
			testFA(L"f2 add 2", flagV2[1], {4, 4, flagVALUE, L"four"});

			FLAG_ARRAY_ENTRY flagArray2[] = {{3, 1, flagVALUE, L"four one"}};
			addin::MergeFlagArrays(flagV2, flagArray2, _countof(flagArray2));
			Assert::AreEqual(size_t{3}, flagV2.size(), L"merge null");
			testFA(L"f2 merge", flagV2[0], {3, 1, flagVALUE, L"four one"});
		}
	};
} // namespace addintest<|endoftext|>


<commit_before>/*
 *  SoapyRedPitaya: Soapy SDR plug-in for Red Pitaya SDR transceiver
 *  Copyright (C) 2015  Pavel Demin
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <string>
#include <sstream>
#include <stdexcept>

#include <stdint.h>
#include <string.h>
#include <unistd.h>

#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif

#include "SoapySDR/Device.hpp"
#include "SoapySDR/Registry.hpp"

#if defined(__APPLE__) || defined(__MACH__)
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL SO_NOSIGPIPE
#endif
#endif

using namespace std;

/***********************************************************************
 * Device interface
 **********************************************************************/

class SoapyRedPitaya : public SoapySDR::Device
{
public:
    SoapyRedPitaya(const SoapySDR::Kwargs &args):
        _addr("192.168.1.100"), _port(1001),
        _freq(6.0e5), _rate(1.0e5), _corr(0.0)
    {
        #ifdef _WIN32
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2, 2), &wsaData);
        #endif

        _sockets[0] = -1;
        _sockets[1] = -1;

        if(args.count("addr")) _addr = args.at("addr");
        if(args.count("port")) stringstream(args.at("port")) >> _port;
    }

    ~SoapyRedPitaya()
    {
        #ifdef _WIN32
        WSACleanup();
        #endif
    }

    /*******************************************************************
     * Identification API
     ******************************************************************/

    string getDriverKey() const
    {
        return "redpitaya";
    }

    string getHardwareKey() const
    {
        return "redpitaya";
    }

    SoapySDR::Kwargs getHardwareInfo() const
    {
        SoapySDR::Kwargs info;
        return info;
    }

    /*******************************************************************
     * Channels API
     ******************************************************************/

    size_t getNumChannels(const int direction) const
    {
        return 1;
    }

    bool getFullDuplex(const int direction, const size_t channel) const
    {
        return true;
    }

    /*******************************************************************
     * Stream API
     ******************************************************************/

    vector<string> getStreamFormats(const int direction, const size_t channel) const
    {
        vector<string> formats;
        formats.push_back("CF32");
        return formats;
    }

    string getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const
    {
        fullScale = 1.0;
        return "CF32";
    }

    SoapySDR::ArgInfoList getStreamArgsInfo(const int direction, const size_t channel) const
    {
        SoapySDR::ArgInfoList streamArgs;
        return streamArgs;
    }

    SoapySDR::Stream *setupStream(
        const int direction,
        const string &format,
        const vector<size_t> &channels = vector<size_t>(),
        const SoapySDR::Kwargs &args = SoapySDR::Kwargs())
    {
        stringstream message;
        struct sockaddr_in addr;
        uint32_t command;

        if(format != "CF32") throw runtime_error("setupStream invalid format " + format);

        if(direction == SOAPY_SDR_RX)
        {
            command = 0;
        }

        if(direction == SOAPY_SDR_TX)
        {
            command = 2;
        }

        for(size_t i = 0; i < 2; ++i)
        {
            if((_sockets[i] = socket(AF_INET, SOCK_STREAM, 0)) < 0)
            {
                throw std::runtime_error("SoapyRedPitaya could not create TCP socket");
            }

            memset(&addr, 0, sizeof(addr));
            addr.sin_family = AF_INET;
            addr.sin_addr.s_addr = inet_addr(_addr.c_str());
            addr.sin_port = htons(_port);

            if(::connect(_sockets[i], (struct sockaddr *)&addr, sizeof(addr)) < 0)
            {
                message << "SoapyRedPitaya could not connect to " << _addr << ":" << _port;
                throw std::runtime_error(message.str());
            }

            sendCommand(_sockets[i], command);

            ++command;
        }
    }

    void closeStream(SoapySDR::Stream *stream)
    {
        ::close(_sockets[1]);
        _sockets[1] = -1;
        ::close(_sockets[0]);
        _sockets[0] = -1;
    }

    size_t getStreamMTU(SoapySDR::Stream *stream) const
    {
        return 2048;
    }

    int activateStream(
        SoapySDR::Stream *stream,
        const int flags = 0,
        const long long timeNs = 0,
        const size_t numElems = 0)
    {
        return 0;
    }

    int deactivateStream(
        SoapySDR::Stream *stream,
        const int flags = 0,
        const long long timeNs = 0)
    {
        return 0;
    }

    int readStream(
        SoapySDR::Stream *stream,
        void * const *buffs,
        const size_t numElems,
        int &flags,
        long long &timeNs,
        const long timeoutUs = 100000)
    {
        struct timeval timeout;
        fd_set readfds;
        int result;

        timeout.tv_sec = timeoutUs / 1000000;
        timeout.tv_usec = timeoutUs % 1000000;

        FD_ZERO(&readfds);
        FD_SET(_sockets[1], &readfds);

        result = select(_sockets[1] + 1, &readfds, NULL, NULL, &timeout);

        if(result < 0) return 0;

        if(result == 0) return SOAPY_SDR_TIMEOUT;

        return ::recv(_sockets[1], buffs[0], 8 * numElems, MSG_WAITALL) / 8;
    }

    int writeStream(
        SoapySDR::Stream *stream,
        const void * const *buffs,
        const size_t numElems,
        int &flags,
        const long long timeNs = 0,
        const long timeoutUs = 100000)
    {
        struct timeval timeout;
        fd_set writefds;
        int result;

        timeout.tv_sec = timeoutUs / 1000000;
        timeout.tv_usec = timeoutUs % 1000000;

        FD_ZERO(&writefds);
        FD_SET(_sockets[1], &writefds);

        result = select(_sockets[1] + 1, NULL, &writefds, NULL, &timeout);

        if(result < 0) return 0;

        if(result == 0) return SOAPY_SDR_TIMEOUT;

        return ::send(_sockets[1], buffs[0], 8 * numElems, MSG_NOSIGNAL) / 8;
    }

    int readStreamStatus(
        SoapySDR::Stream *stream,
        size_t &chanMask,
        int &flags,
        long long &timeNs,
        const long timeoutUs)
    {
        return SOAPY_SDR_NOT_SUPPORTED;
    }

    /*******************************************************************
     * Frequency API
     ******************************************************************/

    void setFrequency(const int direction, const size_t channel, const string &name, const double frequency, const SoapySDR::Kwargs &args = SoapySDR::Kwargs())
    {
        uint32_t command = 0;

        if(name == "BB") return;
        if(name != "RF") throw runtime_error("setFrequency invalid name " + name);

        if(frequency < _rate / 2.0 || frequency > 6.0e7) return;

        command = (uint32_t)floor(frequency * (1.0 + _corr * 1.0e-6) + 0.5);

        sendCommand(_sockets[0], command);

        _freq = frequency;
    }

    double getFrequency(const int direction, const size_t channel, const string &name) const
    {
        if(name == "BB") return 0.0;
        if(name != "RF") throw runtime_error("getFrequency invalid name " + name);
        return _freq;
    }

    vector<string> listFrequencies(const int direction, const size_t channel) const
    {
        vector<string> names;
        names.push_back("RF");
        return names;
    }

    SoapySDR::RangeList getFrequencyRange(const int direction, const size_t channel, const string &name) const
    {
        if (name == "BB") return SoapySDR::RangeList(1, SoapySDR::Range(0.0, 0.0));
        if (name != "RF") throw runtime_error("getFrequencyRange invalid name " + name);
        return SoapySDR::RangeList(1, SoapySDR::Range(_rate / 2.0, 60.0e6));
    }

    /*******************************************************************
     * Sample Rate API
     ******************************************************************/

    void setSampleRate(const int direction, const size_t channel, const double rate)
    {
        uint32_t command = 0;

        if(2.0e4 == rate) command = 0;
        else if(5.0e4 == rate) command = 1;
        else if(1.0e5 == rate) command = 2;
        else if(2.5e5 == rate) command = 3;
        else if(5.0e5 == rate) command = 4;
        else if(1.25e6 == rate) command = 5;

        command |= 1<<28;
        sendCommand(_sockets[0], command);

        _rate = rate;
    }

    double getSampleRate(const int direction, const size_t channel) const
    {
        return _rate;
    }

    vector<double> listSampleRates(const int direction, const size_t channel) const
    {
        vector<double> rates;
        rates.push_back(2.0e4);
        rates.push_back(5.0e4);
        rates.push_back(1.0e5);
        rates.push_back(2.5e5);
        rates.push_back(5.0e5);
        rates.push_back(1.25e6);
        return rates;
    }

private:
    string _addr;
    unsigned short _port;
    double _freq, _rate, _corr;
    int _sockets[2];

    static void sendCommand(int socket, uint32_t command)
    {
        ssize_t size;
        stringstream message;

        size = ::send(socket, &command, sizeof(command), MSG_NOSIGNAL);

        if(size != sizeof(command))
        {
            message << "SoapyRedPitaya sending command failed: " << std::hex << command;
            throw std::runtime_error(message.str());
        }
    }
};

/***********************************************************************
 * Find available devices
 **********************************************************************/
SoapySDR::KwargsList findSoapyRedPitaya(const SoapySDR::Kwargs &args)
{
    vector<SoapySDR::Kwargs> results;
    return results;
}

/***********************************************************************
 * Make device instance
 **********************************************************************/
SoapySDR::Device *makeSoapyRedPitaya(const SoapySDR::Kwargs &args)
{
    return new SoapyRedPitaya(args);
}

/***********************************************************************
 * Registration
 **********************************************************************/
static SoapySDR::Registry registerSoapyRedPitaya("redpitaya", &findSoapyRedPitaya, &makeSoapyRedPitaya, SOAPY_SDR_ABI_VERSION);
<commit_msg>adapt SoapyRedPitaya.cpp to WIN32<commit_after>/*
 *  SoapyRedPitaya: Soapy SDR plug-in for Red Pitaya SDR transceiver
 *  Copyright (C) 2015  Pavel Demin
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <string>
#include <sstream>
#include <stdexcept>

#include <stdint.h>
#include <string.h>
#include <unistd.h>

#if defined(_WIN32) || defined (__CYGWIN__)
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif

#include "SoapySDR/Device.hpp"
#include "SoapySDR/Registry.hpp"

#if defined(__APPLE__) || defined(__MACH__)
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL SO_NOSIGPIPE
#endif
#endif

using namespace std;

/***********************************************************************
 * Device interface
 **********************************************************************/

class SoapyRedPitaya : public SoapySDR::Device
{
public:
    SoapyRedPitaya(const SoapySDR::Kwargs &args):
        _addr("192.168.1.100"), _port(1001),
        _freq(6.0e5), _rate(1.0e5), _corr(0.0)
    {
        #if defined(_WIN32) || defined (__CYGWIN__)
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2, 2), &wsaData);
        #endif

        _sockets[0] = -1;
        _sockets[1] = -1;

        if(args.count("addr")) _addr = args.at("addr");
        if(args.count("port")) stringstream(args.at("port")) >> _port;
    }

    ~SoapyRedPitaya()
    {
        #if defined(_WIN32) || defined (__CYGWIN__)
        WSACleanup();
        #endif
    }

    /*******************************************************************
     * Identification API
     ******************************************************************/

    string getDriverKey() const
    {
        return "redpitaya";
    }

    string getHardwareKey() const
    {
        return "redpitaya";
    }

    SoapySDR::Kwargs getHardwareInfo() const
    {
        SoapySDR::Kwargs info;
        return info;
    }

    /*******************************************************************
     * Channels API
     ******************************************************************/

    size_t getNumChannels(const int direction) const
    {
        return 1;
    }

    bool getFullDuplex(const int direction, const size_t channel) const
    {
        return true;
    }

    /*******************************************************************
     * Stream API
     ******************************************************************/

    vector<string> getStreamFormats(const int direction, const size_t channel) const
    {
        vector<string> formats;
        formats.push_back("CF32");
        return formats;
    }

    string getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const
    {
        fullScale = 1.0;
        return "CF32";
    }

    SoapySDR::ArgInfoList getStreamArgsInfo(const int direction, const size_t channel) const
    {
        SoapySDR::ArgInfoList streamArgs;
        return streamArgs;
    }

    SoapySDR::Stream *setupStream(
        const int direction,
        const string &format,
        const vector<size_t> &channels = vector<size_t>(),
        const SoapySDR::Kwargs &args = SoapySDR::Kwargs())
    {
        stringstream message;
        struct sockaddr_in addr;
        uint32_t command;

        if(format != "CF32") throw runtime_error("setupStream invalid format " + format);

        if(direction == SOAPY_SDR_RX)
        {
            command = 0;
        }

        if(direction == SOAPY_SDR_TX)
        {
            command = 2;
        }

        for(size_t i = 0; i < 2; ++i)
        {
            if((_sockets[i] = ::socket(AF_INET, SOCK_STREAM, 0)) < 0)
            {
                throw runtime_error("SoapyRedPitaya could not create TCP socket");
            }

            memset(&addr, 0, sizeof(addr));
            addr.sin_family = AF_INET;
            addr.sin_addr.s_addr = inet_addr(_addr.c_str());
            addr.sin_port = htons(_port);

            if(::connect(_sockets[i], (struct sockaddr *)&addr, sizeof(addr)) < 0)
            {
                message << "SoapyRedPitaya could not connect to " << _addr << ":" << _port;
                throw runtime_error(message.str());
            }

            sendCommand(_sockets[i], command);

            ++command;
        }

        return 0;
    }

    void closeStream(SoapySDR::Stream *stream)
    {
        ::close(_sockets[1]);
        _sockets[1] = -1;
        ::close(_sockets[0]);
        _sockets[0] = -1;
    }

    size_t getStreamMTU(SoapySDR::Stream *stream) const
    {
        return 2048;
    }

    int activateStream(
        SoapySDR::Stream *stream,
        const int flags = 0,
        const long long timeNs = 0,
        const size_t numElems = 0)
    {
        return 0;
    }

    int deactivateStream(
        SoapySDR::Stream *stream,
        const int flags = 0,
        const long long timeNs = 0)
    {
        return 0;
    }

    int readStream(
        SoapySDR::Stream *stream,
        void * const *buffs,
        const size_t numElems,
        int &flags,
        long long &timeNs,
        const long timeoutUs = 100000)
    {
        unsigned long size = 0;
        struct timeval timeout;

        #if defined(_WIN32) || defined (__CYGWIN__)
        ::ioctlsocket(_sockets[1], FIONREAD, &size);
        #else
        ::ioctl(_sockets[1], FIONREAD, &size);
        #endif

        if(size < 8 * numElems)
        {
            timeout.tv_sec = timeoutUs / 1000000;
            timeout.tv_usec = timeoutUs % 1000000;

            ::select(0, 0, 0, 0, &timeout);

            #if defined(_WIN32) || defined (__CYGWIN__)
            ::ioctlsocket(_sockets[1], FIONREAD, &size);
            #else
            ::ioctl(_sockets[1], FIONREAD, &size);
            #endif
        }

        if(size < 8 * numElems) return SOAPY_SDR_TIMEOUT;

        #if defined(_WIN32) || defined (__CYGWIN__)
        return ::recv(_sockets[1], (char *)buffs[0], 8 * numElems, MSG_WAITALL) / 8;
        #else
        return ::recv(_sockets[1], buffs[0], 8 * numElems, MSG_WAITALL) / 8;
        #endif
    }

    int writeStream(
        SoapySDR::Stream *stream,
        const void * const *buffs,
        const size_t numElems,
        int &flags,
        const long long timeNs = 0,
        const long timeoutUs = 100000)
    {
        ssize_t size;

        #if defined(_WIN32) || defined (__CYGWIN__)
        size = ::send(_sockets[1], (char *)buffs[0], 8 * numElems, 0);
        #else
        size = ::send(_sockets[1], buffs[0], 8 * numElems, MSG_NOSIGNAL);
        #endif

        if(size != 8 * numElems)
        {
            throw runtime_error("writeStream failed");
        }

        return numElems;
    }

    int readStreamStatus(
        SoapySDR::Stream *stream,
        size_t &chanMask,
        int &flags,
        long long &timeNs,
        const long timeoutUs)
    {
        return SOAPY_SDR_NOT_SUPPORTED;
    }

    /*******************************************************************
     * Frequency API
     ******************************************************************/

    void setFrequency(const int direction, const size_t channel, const string &name, const double frequency, const SoapySDR::Kwargs &args = SoapySDR::Kwargs())
    {
        uint32_t command = 0;

        if(name == "BB") return;
        if(name != "RF") throw runtime_error("setFrequency invalid name " + name);

        if(frequency < _rate / 2.0 || frequency > 6.0e7) return;

        command = (uint32_t)floor(frequency * (1.0 + _corr * 1.0e-6) + 0.5);

        sendCommand(_sockets[0], command);

        _freq = frequency;
    }

    double getFrequency(const int direction, const size_t channel, const string &name) const
    {
        if(name == "BB") return 0.0;
        if(name != "RF") throw runtime_error("getFrequency invalid name " + name);
        return _freq;
    }

    vector<string> listFrequencies(const int direction, const size_t channel) const
    {
        vector<string> names;
        names.push_back("RF");
        return names;
    }

    SoapySDR::RangeList getFrequencyRange(const int direction, const size_t channel, const string &name) const
    {
        if (name == "BB") return SoapySDR::RangeList(1, SoapySDR::Range(0.0, 0.0));
        if (name != "RF") throw runtime_error("getFrequencyRange invalid name " + name);
        return SoapySDR::RangeList(1, SoapySDR::Range(_rate / 2.0, 60.0e6));
    }

    /*******************************************************************
     * Sample Rate API
     ******************************************************************/

    void setSampleRate(const int direction, const size_t channel, const double rate)
    {
        uint32_t command = 0;

        if(2.0e4 == rate) command = 0;
        else if(5.0e4 == rate) command = 1;
        else if(1.0e5 == rate) command = 2;
        else if(2.5e5 == rate) command = 3;
        else if(5.0e5 == rate) command = 4;
        else if(1.25e6 == rate) command = 5;

        command |= 1<<28;
        sendCommand(_sockets[0], command);

        _rate = rate;
    }

    double getSampleRate(const int direction, const size_t channel) const
    {
        return _rate;
    }

    vector<double> listSampleRates(const int direction, const size_t channel) const
    {
        vector<double> rates;
        rates.push_back(2.0e4);
        rates.push_back(5.0e4);
        rates.push_back(1.0e5);
        rates.push_back(2.5e5);
        rates.push_back(5.0e5);
        rates.push_back(1.25e6);
        return rates;
    }

private:
    string _addr;
    unsigned short _port;
    double _freq, _rate, _corr;
    int _sockets[2];

    void sendCommand(int socket, uint32_t command)
    {
        ssize_t size;
        stringstream message;

        #if defined(_WIN32) || defined (__CYGWIN__)
        size = ::send(socket, (char *)&command, sizeof(command), 0);
        #else
        size = ::send(socket, &command, sizeof(command), MSG_NOSIGNAL);
        #endif

        if(size != sizeof(command))
        {
            message << "sendCommand failed: " << hex << command;
            throw runtime_error(message.str());
        }
    }
};

/***********************************************************************
 * Find available devices
 **********************************************************************/
SoapySDR::KwargsList findSoapyRedPitaya(const SoapySDR::Kwargs &args)
{
    vector<SoapySDR::Kwargs> results;
    return results;
}

/***********************************************************************
 * Make device instance
 **********************************************************************/
SoapySDR::Device *makeSoapyRedPitaya(const SoapySDR::Kwargs &args)
{
    return new SoapyRedPitaya(args);
}

/***********************************************************************
 * Registration
 **********************************************************************/
static SoapySDR::Registry registerSoapyRedPitaya("redpitaya", &findSoapyRedPitaya, &makeSoapyRedPitaya, SOAPY_SDR_ABI_VERSION);
<|endoftext|>


<commit_before>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/core/distributed_runtime/rpc/grpc_tensor_coding.h"
#include "grpcpp/support/byte_buffer.h"
#include "grpcpp/support/slice.h"
#include "tensorflow/core/common_runtime/dma_helper.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor.pb.h"
#include "tensorflow/core/framework/tensor_reference.h"
#include "tensorflow/core/framework/tensor_shape.pb.h"
#include "tensorflow/core/lib/gtl/inlined_vector.h"
#include "tensorflow/core/lib/io/proto_encode_helper.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/protobuf/worker.pb.h"

namespace tensorflow {
namespace grpc {

void EncodeRecvTensorResponseToByteBuffer(const RecvTensorResponse& proto,
                                          ::grpc::ByteBuffer* result) {
  ::grpc::Slice slice(proto.ByteSizeLong());
  proto.SerializeWithCachedSizesToArray(
      const_cast<uint8*>(reinterpret_cast<const uint8*>(slice.begin())));
  ::grpc::ByteBuffer tmp(&slice, 1);
  result->Swap(&tmp);
}

// We generate a RecvTensorResponse protocol buffer encoding into "*result",
// but where possible, we share the underlying Tensor buffer for "val", to
// avoid an extra copy.
//
// We hand-encode the protocol buffer data in the following order, as follows:
//
// Let R be a RecvTensorResponse object we want to encode, logically
// constructed by filling in data from "is_dead" and "val" and filling
// in a few other fields as well.
//
// (Letters here are used in the code to refer back to which part of the
//  encoding the code is generating).
//
// A:   <protocol buffer encoding of fields except R.tensor()>
// B1:  <tag encoding for RecvTensorResponse::tensor>
// B2:  <varint32 length of R.tensor() sub message>
// C:   <protocol buffer encoding of R.tensor() except for
//          R.tensor().tensor_content()>
// D1:  <tag encoding for TensorProto::tensor_content>
// D2:  <varint32 length of R.tensor().tensor_content() data>
// E:   <actual data for val's representation>
//
// If the tensor data is up to "kLargeTensorBytes", then A
// through E will all be encoded into "*result" in a single grpc::Slice.
//
// If the tensor data is larger than "kLargeTensorBytes", then A through
// D2 will be encoded in one grpc::Slice, and E will be encoded in a second
// grpc::Slice that points to the backing store for the tensor data, to avoid
// copying the tensor data (and the grpc::Slice setup will be arrange so as
// to dereference the underlying tensor data buffer when it is no longer
// needed in the "*result" ByteBuffer).
static int VarLengthEncodingSize(uint32 tag, size_t bytes) {
  return core::VarintLength(tag << 3) + core::VarintLength(bytes) + bytes;
}

// Returns an upper bound in bytes of the protocol buffer encoding of
// the "skeleton" of "val" (all the data needed for dtype and the shape,
// but not the actual contents of "val").
static int SkeletonEncodingSizeUpperBound(const Tensor& val) {
  static const int kVarintMax64 = 10;  // Max length of varint64 encoding
  const int ndims = val.shape().dims();
  return (2 * kVarintMax64) +           // dtype
         (ndims * (4 * kVarintMax64));  // Shape: 4 varints per dim
}

// Encode the skeleton for "val" (the encoded TensorProto contents
// (dtype and shape, but not the actual data) into "*e".  The backing
// store for "*e" must be of appropriate size to hold this encoding.
static void EncodeSkeleton(const Tensor& val, io::ProtoEncodeHelper* e) {
  // Encode val.dtype()
  e->WriteUint64(TensorProto::kDtypeFieldNumber, val.dtype());

  // Compute length of val.shape() proto encoding
  const int ndims = val.shape().dims();
  int tensor_shape_bytes = 0;
  for (int d = 0; d < ndims; d++) {
    int64 dim_size = val.shape().dim_size(d);
    tensor_shape_bytes +=
        2 +  // TensorShapeProto dim tag + varintlength of submessage
        1 +  // TensorShapeProto_Dim::kSizeFieldNumber
        core::VarintLength(dim_size);
  }

  if (tensor_shape_bytes > 0) {
    e->WriteVarlengthBeginning(TensorProto::kTensorShapeFieldNumber,
                               tensor_shape_bytes);
    // Encode val.shape()
    for (int d = 0; d < ndims; d++) {
      int64 dim_size = val.shape().dim_size(d);
      int64 dim_varlen = 1 +  // TensorShapeProto_Dim::kSizeFieldNumber
                         core::VarintLength(dim_size);
      e->WriteVarlengthBeginning(TensorShapeProto::kDimFieldNumber, dim_varlen);
      e->WriteUint64(TensorShapeProto_Dim::kSizeFieldNumber, dim_size);
    }
  }

#ifndef NDEBUG
  {
    // Debug-mode only check to make sure the encoding above is
    // identical to the auto-generated protocol buffer encoding.
    TensorProto skeleton;
    skeleton.set_dtype(val.dtype());
    val.shape().AsProto(skeleton.mutable_tensor_shape());
    string tensor_except_contents;  // tensor() field except contents
    skeleton.AppendToString(&tensor_except_contents);
    TensorProto skeleton2;
    skeleton2.ParseFromString(string(e->data(), e->size()));
    string out;
    skeleton.AppendToString(&out);
    DCHECK_EQ(tensor_except_contents, out) << skeleton.DebugString() << " vs\n"
                                           << skeleton2.DebugString();
  }
#endif
}

void EncodeTensorToByteBuffer(bool is_dead, const Tensor& val,
                              ::grpc::ByteBuffer* result) {
  const int kLargeTensorBytes = 1024;
  RecvTensorResponse response;
  if (is_dead) {
    response.set_is_dead(is_dead);
  }
  response.set_send_start_micros(Env::Default()->NowMicros());
  if (!DataTypeCanUseMemcpy(val.dtype())) {
    // Straightforward but slow path for complicated kinds of tensor data
    // TODO(jeff,sanjay): If this becomes an issue, we could
    // go directly from val -> ByteBuffer, with some effort.
    val.AsProtoTensorContent(response.mutable_tensor());

    // Encode full protocol buffer to a ByteBuffer
    EncodeRecvTensorResponseToByteBuffer(response, result);
  } else {
    // skeleton is the encoded TensorProto contents (dtype and shape), but
    // not the actual data
    gtl::InlinedVector<char, 128> skeleton(SkeletonEncodingSizeUpperBound(val));
    io::ProtoEncodeHelper e_skeleton(skeleton.data(), skeleton.size());
    EncodeSkeleton(val, &e_skeleton);

    StringPiece tdata = val.tensor_data();
    uint32 overall_tensor_proto_bytesize =
        (e_skeleton.size() +
         VarLengthEncodingSize(TensorProto::kTensorContentFieldNumber,
                               tdata.size()));
    string header;  // All of RecvTensorResponse except the tensor() field
    response.AppendToString(&header);

    size_t expected_size =
        (header.size() +
         VarLengthEncodingSize(RecvTensorResponse::kTensorFieldNumber,
                               overall_tensor_proto_bytesize));
    // If "tensor_data_is_large == false", we copy the tensor data to the
    // end of the buffer we are preparing that holds the rest of the
    // RecvTensorResponse protocol buffer.
    //
    // If "tensor_data_is_large == true", we arrange to share the backing
    // store of the data by creating a slice that also points to the
    // backing store, with appropriate reference counts to keep the
    // backing store alive as needed.
    bool tensor_data_is_large = (tdata.size() > kLargeTensorBytes);
    size_t encoder_size = expected_size - tdata.size();

    // Encode all but the actual "tdata", but including the tag and
    // varlength header for the "tdata"
    gtl::InlinedVector<char, 1024> space(encoder_size);
    io::ProtoEncodeHelper e(space.data(), space.size());
    // (A)
    e.WriteRawBytes(header);

    // (B1) & (B2)
    e.WriteVarlengthBeginning(RecvTensorResponse::kTensorFieldNumber,
                              overall_tensor_proto_bytesize);
    // (C)
    e.WriteRawBytes(StringPiece(e_skeleton.data(), e_skeleton.size()));
    // (D1) & (D2)
    e.WriteVarlengthBeginning(TensorProto::kTensorContentFieldNumber,
                              tdata.size());

    // All but the tensor backing store are serialized now

    // Now allocate memory and put into the ByteBuffer
    ::grpc::Slice slices[2];
    int num_slices = 0;
    {
      size_t slice_len = e.size() + (tensor_data_is_large ? 0 : tdata.size());
      slices[0] = ::grpc::Slice(slice_len);
      memcpy(const_cast<uint8_t*>(slices[0].begin()), e.data(), e.size());
      if (!tensor_data_is_large) {
        // (E)
        memcpy(const_cast<uint8_t*>(slices[0].begin()) + e.size(), tdata.data(),
               tdata.size());
      }
      num_slices += 1;
    }

    if (tensor_data_is_large) {
      // (E) Encode tensor data, but by sharing backing store
      const TensorBuffer* buf = DMAHelper::buffer(&val);
      buf->Ref();
      slices[1] = ::grpc::Slice(
          const_cast<void*>(static_cast<const void*>(tdata.data())),
          tdata.size(),
          [](void* backing) { static_cast<TensorBuffer*>(backing)->Unref(); },
          const_cast<TensorBuffer*>(buf));
      num_slices += 1;
    }
    size_t total_bytes = 0;
    for (int i = 0; i < num_slices; i++) {
      total_bytes += slices[i].size();
    }
    CHECK_EQ(total_bytes, expected_size);

    ::grpc::ByteBuffer tmp(&slices[0], num_slices);
    result->Swap(&tmp);
  }
}

}  // namespace grpc
}  // namespace tensorflow
<commit_msg>Rename tensor_data_is_large to share_tensor_slice_memory<commit_after>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/core/distributed_runtime/rpc/grpc_tensor_coding.h"
#include "grpcpp/support/byte_buffer.h"
#include "grpcpp/support/slice.h"
#include "tensorflow/core/common_runtime/dma_helper.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor.pb.h"
#include "tensorflow/core/framework/tensor_reference.h"
#include "tensorflow/core/framework/tensor_shape.pb.h"
#include "tensorflow/core/lib/gtl/inlined_vector.h"
#include "tensorflow/core/lib/io/proto_encode_helper.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/protobuf/worker.pb.h"

// (Omitted internal-only flag)

namespace tensorflow {
namespace grpc {

void EncodeRecvTensorResponseToByteBuffer(const RecvTensorResponse& proto,
                                          ::grpc::ByteBuffer* result) {
  ::grpc::Slice slice(proto.ByteSizeLong());
  proto.SerializeWithCachedSizesToArray(
      const_cast<uint8*>(reinterpret_cast<const uint8*>(slice.begin())));
  ::grpc::ByteBuffer tmp(&slice, 1);
  result->Swap(&tmp);
}

// We generate a RecvTensorResponse protocol buffer encoding into "*result",
// but where possible, we share the underlying Tensor buffer for "val", to
// avoid an extra copy.
//
// We hand-encode the protocol buffer data in the following order, as follows:
//
// Let R be a RecvTensorResponse object we want to encode, logically
// constructed by filling in data from "is_dead" and "val" and filling
// in a few other fields as well.
//
// (Letters here are used in the code to refer back to which part of the
//  encoding the code is generating).
//
// A:   <protocol buffer encoding of fields except R.tensor()>
// B1:  <tag encoding for RecvTensorResponse::tensor>
// B2:  <varint32 length of R.tensor() sub message>
// C:   <protocol buffer encoding of R.tensor() except for
//          R.tensor().tensor_content()>
// D1:  <tag encoding for TensorProto::tensor_content>
// D2:  <varint32 length of R.tensor().tensor_content() data>
// E:   <actual data for val's representation>
//
// If the tensor data is up to "kLargeTensorBytes", then A
// through E will all be encoded into "*result" in a single grpc::Slice.
//
// If the tensor data is larger than "kLargeTensorBytes", then A through
// D2 will be encoded in one grpc::Slice, and E will be encoded in a second
// grpc::Slice that points to the backing store for the tensor data, to avoid
// copying the tensor data (and the grpc::Slice setup will be arrange so as
// to dereference the underlying tensor data buffer when it is no longer
// needed in the "*result" ByteBuffer).
static int VarLengthEncodingSize(uint32 tag, size_t bytes) {
  return core::VarintLength(tag << 3) + core::VarintLength(bytes) + bytes;
}

// Returns an upper bound in bytes of the protocol buffer encoding of
// the "skeleton" of "val" (all the data needed for dtype and the shape,
// but not the actual contents of "val").
static int SkeletonEncodingSizeUpperBound(const Tensor& val) {
  static const int kVarintMax64 = 10;  // Max length of varint64 encoding
  const int ndims = val.shape().dims();
  return (2 * kVarintMax64) +           // dtype
         (ndims * (4 * kVarintMax64));  // Shape: 4 varints per dim
}

// Encode the skeleton for "val" (the encoded TensorProto contents
// (dtype and shape, but not the actual data) into "*e".  The backing
// store for "*e" must be of appropriate size to hold this encoding.
static void EncodeSkeleton(const Tensor& val, io::ProtoEncodeHelper* e) {
  // Encode val.dtype()
  e->WriteUint64(TensorProto::kDtypeFieldNumber, val.dtype());

  // Compute length of val.shape() proto encoding
  const int ndims = val.shape().dims();
  int tensor_shape_bytes = 0;
  for (int d = 0; d < ndims; d++) {
    int64 dim_size = val.shape().dim_size(d);
    tensor_shape_bytes +=
        2 +  // TensorShapeProto dim tag + varintlength of submessage
        1 +  // TensorShapeProto_Dim::kSizeFieldNumber
        core::VarintLength(dim_size);
  }

  if (tensor_shape_bytes > 0) {
    e->WriteVarlengthBeginning(TensorProto::kTensorShapeFieldNumber,
                               tensor_shape_bytes);
    // Encode val.shape()
    for (int d = 0; d < ndims; d++) {
      int64 dim_size = val.shape().dim_size(d);
      int64 dim_varlen = 1 +  // TensorShapeProto_Dim::kSizeFieldNumber
                         core::VarintLength(dim_size);
      e->WriteVarlengthBeginning(TensorShapeProto::kDimFieldNumber, dim_varlen);
      e->WriteUint64(TensorShapeProto_Dim::kSizeFieldNumber, dim_size);
    }
  }

#ifndef NDEBUG
  {
    // Debug-mode only check to make sure the encoding above is
    // identical to the auto-generated protocol buffer encoding.
    TensorProto skeleton;
    skeleton.set_dtype(val.dtype());
    val.shape().AsProto(skeleton.mutable_tensor_shape());
    string tensor_except_contents;  // tensor() field except contents
    skeleton.AppendToString(&tensor_except_contents);
    TensorProto skeleton2;
    skeleton2.ParseFromString(string(e->data(), e->size()));
    string out;
    skeleton.AppendToString(&out);
    DCHECK_EQ(tensor_except_contents, out) << skeleton.DebugString() << " vs\n"
                                           << skeleton2.DebugString();
  }
#endif
}

void EncodeTensorToByteBuffer(bool is_dead, const Tensor& val,
                              ::grpc::ByteBuffer* result) {
  const int kLargeTensorBytes = 1024;
  RecvTensorResponse response;
  if (is_dead) {
    response.set_is_dead(is_dead);
  }
  response.set_send_start_micros(Env::Default()->NowMicros());
  if (!DataTypeCanUseMemcpy(val.dtype())) {
    // Straightforward but slow path for complicated kinds of tensor data
    // TODO(jeff,sanjay): If this becomes an issue, we could
    // go directly from val -> ByteBuffer, with some effort.
    val.AsProtoTensorContent(response.mutable_tensor());

    // Encode full protocol buffer to a ByteBuffer
    EncodeRecvTensorResponseToByteBuffer(response, result);
  } else {
    // skeleton is the encoded TensorProto contents (dtype and shape), but
    // not the actual data
    gtl::InlinedVector<char, 128> skeleton(SkeletonEncodingSizeUpperBound(val));
    io::ProtoEncodeHelper e_skeleton(skeleton.data(), skeleton.size());
    EncodeSkeleton(val, &e_skeleton);

    StringPiece tdata = val.tensor_data();
    uint32 overall_tensor_proto_bytesize =
        (e_skeleton.size() +
         VarLengthEncodingSize(TensorProto::kTensorContentFieldNumber,
                               tdata.size()));
    string header;  // All of RecvTensorResponse except the tensor() field
    response.AppendToString(&header);

    size_t expected_size =
        (header.size() +
         VarLengthEncodingSize(RecvTensorResponse::kTensorFieldNumber,
                               overall_tensor_proto_bytesize));
    // If "share_tensor_slice_memory == false", we copy the tensor data to
    // the end of the buffer we are preparing that holds the rest of the
    // RecvTensorResponse protocol buffer.
    //
    // If "share_tensor_slice_memory == true", we arrange to share the
    // backing store of the data by creating a slice that also points to the
    // backing store, with appropriate reference counts to keep the
    // backing store alive as needed.
    //
    // We enable this behavior if the tensor is large.
    bool share_tensor_slice_memory = (tdata.size() > kLargeTensorBytes);

    // (Omitted internal-only conditional)

    size_t encoder_size = expected_size - tdata.size();

    // Encode all but the actual "tdata", but including the tag and
    // varlength header for the "tdata"
    gtl::InlinedVector<char, 1024> space(encoder_size);
    io::ProtoEncodeHelper e(space.data(), space.size());
    // (A)
    e.WriteRawBytes(header);

    // (B1) & (B2)
    e.WriteVarlengthBeginning(RecvTensorResponse::kTensorFieldNumber,
                              overall_tensor_proto_bytesize);
    // (C)
    e.WriteRawBytes(StringPiece(e_skeleton.data(), e_skeleton.size()));
    // (D1) & (D2)
    e.WriteVarlengthBeginning(TensorProto::kTensorContentFieldNumber,
                              tdata.size());

    // All but the tensor backing store are serialized now

    // Now allocate memory and put into the ByteBuffer
    ::grpc::Slice slices[2];
    int num_slices = 0;
    {
      size_t slice_len =
          e.size() + (share_tensor_slice_memory ? 0 : tdata.size());
      slices[0] = ::grpc::Slice(slice_len);
      memcpy(const_cast<uint8_t*>(slices[0].begin()), e.data(), e.size());
      if (!share_tensor_slice_memory) {
        // (E)
        memcpy(const_cast<uint8_t*>(slices[0].begin()) + e.size(), tdata.data(),
               tdata.size());
      }
      num_slices += 1;
    }

    if (share_tensor_slice_memory) {
      // (E) Encode tensor data, but by sharing backing store
      const TensorBuffer* buf = DMAHelper::buffer(&val);
      buf->Ref();
      slices[1] = ::grpc::Slice(
          const_cast<void*>(static_cast<const void*>(tdata.data())),
          tdata.size(),
          [](void* backing) { static_cast<TensorBuffer*>(backing)->Unref(); },
          const_cast<TensorBuffer*>(buf));
      num_slices += 1;
    }
    size_t total_bytes = 0;
    for (int i = 0; i < num_slices; i++) {
      total_bytes += slices[i].size();
    }
    CHECK_EQ(total_bytes, expected_size);

    ::grpc::ByteBuffer tmp(&slices[0], num_slices);
    result->Swap(&tmp);
  }
}

}  // namespace grpc
}  // namespace tensorflow
<|endoftext|>