<commit_before>#include "core.h"
#include "debug.h"

#include "network_mesh_analytical.h"
//#define CORE_DEBUG

using namespace std;

int Core::coreInit(Chip *chip, int tid, int num_mod)
{
   the_chip = chip;
   core_tid = tid;
   core_num_mod = num_mod;

   //Switch which line is commented to choose the different
   //network models
   //FIXME: Make this runtime configurable
   //NetworkModel net_model = NETWORK_BUS;
   NetworkModel net_model = NETWORK_ANALYTICAL_MESH;

   switch(net_model)
   {
       case NETWORK_BUS:
           network = new Network(chip, tid, num_mod, this);
           break;
       case NETWORK_ANALYTICAL_MESH:
           network = new NetworkMeshAnalytical(chip, tid, num_mod, this);
           break;
       case NUM_NETWORK_TYPES:
       default:
           cout << "ERROR: Unknown Network Model!";
           break;
   }

   if ( g_knob_enable_performance_modeling )
   {
      perf_model = new PerfModel("performance modeler");
      debugPrint(tid, "Core", "instantiated performance model");
   } else
   {
      perf_model = (PerfModel *) NULL;
   }

   if ( g_knob_enable_dcache_modeling || g_knob_enable_icache_modeling )
   {
      ocache = new OCache("organic cache",
                          g_knob_cache_size.Value() * k_KILO,
                          g_knob_line_size.Value(),
                          g_knob_associativity.Value(),
                          g_knob_mutation_interval.Value(),
                          g_knob_dcache_threshold_hit.Value(),
                          g_knob_dcache_threshold_miss.Value(),
                          g_knob_dcache_size.Value() * k_KILO,
                          g_knob_dcache_associativity.Value(),
                          g_knob_dcache_max_search_depth.Value(),
                          g_knob_icache_threshold_hit.Value(),
                          g_knob_icache_threshold_miss.Value(),
                          g_knob_icache_size.Value() * k_KILO,
                          g_knob_icache_associativity.Value(),
                          g_knob_icache_max_search_depth.Value());
//                          g_knob_simarch_is_shared_mem.Value());

      debugPrint(tid, "Core", "instantiated organic cache model");
      cout << ocache->statsLong() << endl;

   } else
   {
      ocache = (OCache *) NULL;
   }

   if ( g_knob_simarch_has_shared_mem ) {

      assert( g_knob_enable_dcache_modeling );

      cerr << "Core[" << tid << "]: instantiated memory manager model" << endl;
      memory_manager = new MemoryManager(this, ocache);

   } else {

      memory_manager = (MemoryManager *) NULL;
      cerr << "No Memory Manager being used. " << endl;

   }

   syscall_model = new SyscallMdl(network);
   InitLock(&dcache_lock);

   return 0;
}

int Core::coreCommID() { return network->netCommID(); }

int Core::coreSendW(int sender, int receiver, char *buffer, int size)
{
   // Create a net packet
   NetPacket packet;
   packet.sender= sender;
   packet.receiver= receiver;
   packet.type = USER;
   packet.length = size;
   packet.data = buffer;

   /*
   packet.data = new char[size];
   for(int i = 0; i < size; i++)
      packet.data[i] = buffer[i];
   */

   network->netSend(packet);
   return 0;
}

int Core::coreRecvW(int sender, int receiver, char *buffer, int size)
{
   NetPacket packet;
   NetMatch match;

   match.sender = sender;
   match.sender_flag = true;
   match.type = USER;
   match.type_flag = true;

   packet = network->netRecv(match);

#ifdef DEBUG
   cout << "Got packet: "
	<< "Send=" << packet.sender
	<< ", Recv=" << packet.receiver
	<< ", Type=" << packet.type
	<< ", Len=" << packet.length << endl;
#endif

   if((unsigned)size != packet.length){
      cerr << "ERROR (comm_id: " << coreCommID() << "):" << endl
           << "Received packet length (" << packet.length
	   << ") is not as expected (" << size << ")" << endl;
      exit(-1);
   }

   for(int i = 0; i < size; i++)
      buffer[i] = packet.data[i];

   // De-allocate dynamic memory
   delete [] packet.data;

   return 0;
}

Network* Core::getNetwork()
{
  return network;
}

VOID Core::fini(int code, VOID *v, ofstream& out)
{
   delete network;

   if ( g_knob_enable_performance_modeling )
      perf_model->fini(code, v, out);

   if ( g_knob_enable_dcache_modeling || g_knob_enable_icache_modeling )
      ocache->fini(code,v,out);
}

//performance model wrappers

//these have been moved into the .h file
//m VOID Core::perfModelRun(PerfModelIntervalStat *interval_stats)
//m { perf_model->run(interval_stats); }

//VOID Core::perfModelRun(PerfModelIntervalStat *interval_stats, REG *reads,
//						 UINT32 num_reads)
//{ perf_model->run(interval_stats, reads, num_reads); }

//VOID Core::perfModelRun(PerfModelIntervalStat *interval_stats, bool dcache_load_hit,
//						 REG *writes, UINT32 num_writes)
//{ perf_model->run(interval_stats, dcache_load_hit, writes, num_writes); }

//PerfModelIntervalStat* Core::perfModelAnalyzeInterval(const string& parent_routine,
//													   const INS& start_ins,
//													   const INS& end_ins)
//{ return perf_model->analyzeInterval(parent_routine, start_ins, end_ins); }

//VOID Core::perfModelLogICacheLoadAccess(PerfModelIntervalStat *stats, bool hit)
//{ perf_model->logICacheLoadAccess(stats, hit); }

//VOID Core::perfModelLogDCacheStoreAccess(PerfModelIntervalStat *stats, bool hit)
//{ perf_model->logDCacheStoreAccess(stats, hit); }

//VOID Core::perfModelLogBranchPrediction(PerfModelIntervalStat *stats, bool correct)
//{ perf_model->logBranchPrediction(stats, correct); }

// organic cache wrappers

bool Core::icacheRunLoadModel(ADDRINT i_addr, UINT32 size)
{ return ocache->runICacheLoadModel(i_addr, size).first; }

/*
 * dcacheRunModel (mem_operation_t operation, ADDRINT d_addr, char* data_buffer, UINT32 data_size)
 *
 * Arguments:
 *   d_addr :: address of location we want to access (read or write)
 *   shmem_req_t :: READ or WRITE
 *   data_buffer :: buffer holding data for WRITE or buffer which must be written on a READ
 *   data_size :: size of data we must read/write
 *
 * Return Value:
 *   hit :: Say whether there has been at least one cache hit or not
 */
bool Core::dcacheRunModel(mem_operation_t operation, ADDRINT d_addr, char* data_buffer, UINT32 data_size)
{
	shmem_req_t shmem_operation;

	if (operation == LOAD)
		shmem_operaiton = READ;
	else
		shmem_operation = WRITE;

	if (g_knob_simarch_has_shared_mem) {

		bool all_hits = true;

		if (size <= 0) {
			return (false);
			// FIXME: Why false - we are not encountering any cache misses anyway
		}

#ifdef SMEM_DEBUG
       debugPrint(getRank(), "CORE", "dcache initiating shared memory request (READ)");
#endif

		ADDRINT begin_addr = d_addr;
		ADDRINT end_addr = d_addr + data_size;
	   	ADDRINT begin_addr_aligned = begin_addr - (begin_addr % ocache->dCacheLineSize());
		ADDRINT end_addr_aligned = end_addr - (end_addr % ocache->dCacheLineSize());
		char *curr_data_buffer_head = data_buffer;

		for (ADDRINT curr_addr_aligned = begin_addr_aligned ; curr_addr_aligned <= end_addr_aligned /* Note <= */; curr_addr_aligned += ocache->dCacheLineSize())
		{
			// Access the cache one line at a time
			ADDRINT curr_offset;
			UINT32 curr_size;

			// Determine the offset
			if (curr_addr_aligned == begin_addr_aligned) {
				curr_offset = begin_addr % ocache->dCacheLineSize();
			}
			else {
				curr_offset = 0;
			}

			// Determine the size
			if (curr_addr_aligned = end_addr_aligned) {
				curr_size = (end_addr % ocache->dCacheLineSize()) - (curr_offset);
			}
			else {
				curr_size = ocache->dCacheLineSize();
			}

			if (!memory_manager->initiateSharedMemReq (shmem_operation, curr_addr_aligned, curr_offset, curr_data_buffer_head, curr_size)) {
				// If it is a LOAD operation, 'initiateSharedMemReq' causes curr_data_buffer_head to be automatically filled in
				// If it is a STORE operation, 'initiateSharedMemReq' reads the data from curr_data_buffer_head
				all_hits = false;
			}

			// Increment the buffer head
			curr_data_buffer_head += curr_size;
		}

		//NOTE: this method of multi-line accesses cache-aligns the addresses.
		//TODO have this deal with data
			//access one cache line at a time
			//TODO set the size parameter correctly, based on the size of the data buffer
			//TODO does this spill over to another line? should shared_mem test look at other DRAM entries?
			//the "0" below is the addr_offset. important for partial-line operations when the data_size is less than cache_line_size

//		debugPrint(getRank(), "Core", "FINISHED ---- TRapping into SHARED_MEMORY");
		return all_hits;

	}
	else {
	   	//run this if we aren't using shared_memory
		// FIXME: I am not sure this is right
		if(operation == LOAD)
			return ocache->runDCacheLoadModel(d_addr, size).first;
	   	else
			return ocache->runDCacheStoreModel(d_addr, size).first;
   	}
}

void Core::debugSetCacheState(ADDRINT address, CacheState::cstate_t cstate)
{
	//using Load Model, so that way we garuntee the tag isn't null
	pair<bool, CacheTag*> cache_result;

	switch(cstate) {
		case CacheState::INVALID:
			ocache->dCacheInvalidateLine(address);
			break;
		case CacheState::SHARED:
			cache_result = ocache->runDCacheLoadModel(address,1);
			cache_result.second->setCState(cstate);
			break;
		case CacheState::EXCLUSIVE:
			cache_result = ocache->runDCacheLoadModel(address,1);
			cache_result.second->setCState(cstate);
			break;
		default:
			cout << "ERROR in switch for Core::debugSetCacheState" << endl;
	}
}

bool Core::debugAssertCacheState(ADDRINT address, CacheState::cstate_t expected_cstate)
{
//	pair<bool,CacheTag*> cache_result = ocache->runDCachePeekModel(address, 1);
	pair<bool,CacheTag*> cache_result = ocache->runDCachePeekModel(address);

	bool is_assert_true;
   CacheState::cstate_t actual_cstate;

	if( cache_result.second != NULL ) {
		actual_cstate = cache_result.second->getCState();
		is_assert_true = ( actual_cstate  == expected_cstate );
	} else {
		actual_cstate = CacheState::INVALID;
		is_assert_true = ( actual_cstate  == expected_cstate );
	}

	cerr << "   Asserting Cache[" << getRank() << "] : Expected: " << CacheState::cStateToString(expected_cstate) << " ,  Actual: " <<  CacheState::cStateToString(actual_cstate);

	if(is_assert_true) {
      cerr << "                    TEST PASSED " << endl;
	} else {
		cerr << "                    TEST FAILED ****** " << endl;
	}

	return is_assert_true;

}

void Core::debugSetDramState(ADDRINT address, DramDirectoryEntry::dstate_t dstate, vector<UINT32> sharers_list)
{
	memory_manager->debugSetDramState(address, dstate, sharers_list);
}

bool Core::debugAssertDramState(ADDRINT address, DramDirectoryEntry::dstate_t dstate, vector<UINT32> sharers_list)
{
	return memory_manager->debugAssertDramState(address, dstate, sharers_list);

}

/*
void Core::setDramBoundaries(vector< pair<ADDRINT, ADDRINT> > addr_boundaries)
{
	cerr << "CORE: setting dram boundaries" << endl;
	assert( g_knob_simarch_has_shared_mem );
	memory_manager->setDramBoundaries(addr_boundaries);
	cerr << "CORE: finished setting dram boundaries" << endl;
}
*/
<commit_msg>Finished hopefully making the changes to 'core.cc' for adding data handling<commit_after>#include "core.h"
#include "debug.h"

#include "network_mesh_analytical.h"
//#define CORE_DEBUG

using namespace std;

int Core::coreInit(Chip *chip, int tid, int num_mod)
{
   the_chip = chip;
   core_tid = tid;
   core_num_mod = num_mod;

   //Switch which line is commented to choose the different
   //network models
   //FIXME: Make this runtime configurable
   //NetworkModel net_model = NETWORK_BUS;
   NetworkModel net_model = NETWORK_ANALYTICAL_MESH;

   switch(net_model)
   {
       case NETWORK_BUS:
           network = new Network(chip, tid, num_mod, this);
           break;
       case NETWORK_ANALYTICAL_MESH:
           network = new NetworkMeshAnalytical(chip, tid, num_mod, this);
           break;
       case NUM_NETWORK_TYPES:
       default:
           cout << "ERROR: Unknown Network Model!";
           break;
   }

   if ( g_knob_enable_performance_modeling )
   {
      perf_model = new PerfModel("performance modeler");
      debugPrint(tid, "Core", "instantiated performance model");
   } else
   {
      perf_model = (PerfModel *) NULL;
   }

   if ( g_knob_enable_dcache_modeling || g_knob_enable_icache_modeling )
   {
      ocache = new OCache("organic cache",
                          g_knob_cache_size.Value() * k_KILO,
                          g_knob_line_size.Value(),
                          g_knob_associativity.Value(),
                          g_knob_mutation_interval.Value(),
                          g_knob_dcache_threshold_hit.Value(),
                          g_knob_dcache_threshold_miss.Value(),
                          g_knob_dcache_size.Value() * k_KILO,
                          g_knob_dcache_associativity.Value(),
                          g_knob_dcache_max_search_depth.Value(),
                          g_knob_icache_threshold_hit.Value(),
                          g_knob_icache_threshold_miss.Value(),
                          g_knob_icache_size.Value() * k_KILO,
                          g_knob_icache_associativity.Value(),
                          g_knob_icache_max_search_depth.Value());
//                          g_knob_simarch_is_shared_mem.Value());

      debugPrint(tid, "Core", "instantiated organic cache model");
      cout << ocache->statsLong() << endl;

   } else
   {
      ocache = (OCache *) NULL;
   }

   if ( g_knob_simarch_has_shared_mem ) {

      assert( g_knob_enable_dcache_modeling );

      cerr << "Core[" << tid << "]: instantiated memory manager model" << endl;
      memory_manager = new MemoryManager(this, ocache);

   } else {

      memory_manager = (MemoryManager *) NULL;
      cerr << "No Memory Manager being used. " << endl;

   }

   syscall_model = new SyscallMdl(network);
   InitLock(&dcache_lock);

   return 0;
}

int Core::coreCommID() { return network->netCommID(); }

int Core::coreSendW(int sender, int receiver, char *buffer, int size)
{
   // Create a net packet
   NetPacket packet;
   packet.sender= sender;
   packet.receiver= receiver;
   packet.type = USER;
   packet.length = size;
   packet.data = buffer;

   /*
   packet.data = new char[size];
   for(int i = 0; i < size; i++)
      packet.data[i] = buffer[i];
   */

   network->netSend(packet);
   return 0;
}

int Core::coreRecvW(int sender, int receiver, char *buffer, int size)
{
   NetPacket packet;
   NetMatch match;

   match.sender = sender;
   match.sender_flag = true;
   match.type = USER;
   match.type_flag = true;

   packet = network->netRecv(match);

#ifdef DEBUG
   cout << "Got packet: "
	<< "Send=" << packet.sender
	<< ", Recv=" << packet.receiver
	<< ", Type=" << packet.type
	<< ", Len=" << packet.length << endl;
#endif

   if((unsigned)size != packet.length){
      cerr << "ERROR (comm_id: " << coreCommID() << "):" << endl
           << "Received packet length (" << packet.length
	   << ") is not as expected (" << size << ")" << endl;
      exit(-1);
   }

   for(int i = 0; i < size; i++)
      buffer[i] = packet.data[i];

   // De-allocate dynamic memory
   delete [] packet.data;

   return 0;
}

Network* Core::getNetwork()
{
  return network;
}

VOID Core::fini(int code, VOID *v, ofstream& out)
{
   delete network;

   if ( g_knob_enable_performance_modeling )
      perf_model->fini(code, v, out);

   if ( g_knob_enable_dcache_modeling || g_knob_enable_icache_modeling )
      ocache->fini(code,v,out);
}

//performance model wrappers

//these have been moved into the .h file
//m VOID Core::perfModelRun(PerfModelIntervalStat *interval_stats)
//m { perf_model->run(interval_stats); }

//VOID Core::perfModelRun(PerfModelIntervalStat *interval_stats, REG *reads,
//						 UINT32 num_reads)
//{ perf_model->run(interval_stats, reads, num_reads); }

//VOID Core::perfModelRun(PerfModelIntervalStat *interval_stats, bool dcache_load_hit,
//						 REG *writes, UINT32 num_writes)
//{ perf_model->run(interval_stats, dcache_load_hit, writes, num_writes); }

//PerfModelIntervalStat* Core::perfModelAnalyzeInterval(const string& parent_routine,
//													   const INS& start_ins,
//													   const INS& end_ins)
//{ return perf_model->analyzeInterval(parent_routine, start_ins, end_ins); }

//VOID Core::perfModelLogICacheLoadAccess(PerfModelIntervalStat *stats, bool hit)
//{ perf_model->logICacheLoadAccess(stats, hit); }

//VOID Core::perfModelLogDCacheStoreAccess(PerfModelIntervalStat *stats, bool hit)
//{ perf_model->logDCacheStoreAccess(stats, hit); }

//VOID Core::perfModelLogBranchPrediction(PerfModelIntervalStat *stats, bool correct)
//{ perf_model->logBranchPrediction(stats, correct); }

// organic cache wrappers

bool Core::icacheRunLoadModel(ADDRINT i_addr, UINT32 size)
{ return ocache->runICacheLoadModel(i_addr, size).first; }

/*
 * dcacheRunModel (mem_operation_t operation, ADDRINT d_addr, char* data_buffer, UINT32 data_size)
 *
 * Arguments:
 *   d_addr :: address of location we want to access (read or write)
 *   shmem_req_t :: READ or WRITE
 *   data_buffer :: buffer holding data for WRITE or buffer which must be written on a READ
 *   data_size :: size of data we must read/write
 *
 * Return Value:
 *   hit :: Say whether there has been at least one cache hit or not
 */
bool Core::dcacheRunModel(mem_operation_t operation, ADDRINT d_addr, char* data_buffer, UINT32 data_size)
{
	shmem_req_t shmem_operation;

	if (operation == LOAD)
		shmem_operaiton = READ;
	else
		shmem_operation = WRITE;

	if (g_knob_simarch_has_shared_mem)  {

		bool all_hits = true;

		if (size <= 0) {
			return (false);
			// FIXME: Why false - we are not encountering any cache misses anyway
		}

#ifdef SMEM_DEBUG
       debugPrint(getRank(), "CORE", "dcache initiating shared memory request (READ)");
#endif

		ADDRINT begin_addr = d_addr;
		ADDRINT end_addr = d_addr + data_size;
	   	ADDRINT begin_addr_aligned = begin_addr - (begin_addr % ocache->dCacheLineSize());
		ADDRINT end_addr_aligned = end_addr - (end_addr % ocache->dCacheLineSize());
		char *curr_data_buffer_head = data_buffer;

		for (ADDRINT curr_addr_aligned = begin_addr_aligned ; curr_addr_aligned <= end_addr_aligned /* Note <= */; curr_addr_aligned += ocache->dCacheLineSize())
		{
			// Access the cache one line at a time
			ADDRINT curr_offset;
			UINT32 curr_size;

			// Determine the offset
			if (curr_addr_aligned == begin_addr_aligned) {
				curr_offset = begin_addr % ocache->dCacheLineSize();
			}
			else {
				curr_offset = 0;
			}

			// Determine the size
			if (curr_addr_aligned = end_addr_aligned) {
				curr_size = (end_addr % ocache->dCacheLineSize()) - (curr_offset);
			}
			else {
				curr_size = ocache->dCacheLineSize();
			}

			if (!memory_manager->initiateSharedMemReq (shmem_operation, curr_addr_aligned, curr_offset, curr_data_buffer_head, curr_size)) {
				// If it is a LOAD operation, 'initiateSharedMemReq' causes curr_data_buffer_head to be automatically filled in
				// If it is a STORE operation, 'initiateSharedMemReq' reads the data from curr_data_buffer_head
				all_hits = false;
			}

			// Increment the buffer head
			curr_data_buffer_head += curr_size;
		}

		//NOTE: this method of multi-line accesses cache-aligns the addresses.
		//TODO have this deal with data
			//access one cache line at a time
			//TODO set the size parameter correctly, based on the size of the data buffer
			//TODO does this spill over to another line? should shared_mem test look at other DRAM entries?
			//the "0" below is the addr_offset. important for partial-line operations when the data_size is less than cache_line_size

//		debugPrint(getRank(), "Core", "FINISHED ---- TRapping into SHARED_MEMORY");
		return all_hits;

	}
	else {
	   	//run this if we aren't using shared_memory
		// FIXME: I am not sure this is right
		if(operation == LOAD)
			return ocache->runDCacheLoadModel(d_addr, size).first;
	   	else
			return ocache->runDCacheStoreModel(d_addr, size).first;
   	}
}

void Core::debugSetCacheState(ADDRINT address, CacheState::cstate_t cstate)
{
	//using Load Model, so that way we garuntee the tag isn't null
	pair<bool, CacheTag*> cache_result;

	switch(cstate) {
		case CacheState::INVALID:
			ocache->dCacheInvalidateLine(address);
			break;
		case CacheState::SHARED:
			cache_result = ocache->runDCacheLoadModel(address,1);
			cache_result.second->setCState(cstate);
			break;
		case CacheState::EXCLUSIVE:
			cache_result = ocache->runDCacheLoadModel(address,1);
			cache_result.second->setCState(cstate);
			break;
		default:
			cout << "ERROR in switch for Core::debugSetCacheState" << endl;
	}
}

bool Core::debugAssertCacheState(ADDRINT address, CacheState::cstate_t expected_cstate)
{
//	pair<bool,CacheTag*> cache_result = ocache->runDCachePeekModel(address, 1);
	pair<bool,CacheTag*> cache_result = ocache->runDCachePeekModel(address);

	bool is_assert_true;
   CacheState::cstate_t actual_cstate;

	if( cache_result.second != NULL ) {
		actual_cstate = cache_result.second->getCState();
		is_assert_true = ( actual_cstate  == expected_cstate );
	} else {
		actual_cstate = CacheState::INVALID;
		is_assert_true = ( actual_cstate  == expected_cstate );
	}

	cerr << "   Asserting Cache[" << getRank() << "] : Expected: " << CacheState::cStateToString(expected_cstate) << " ,  Actual: " <<  CacheState::cStateToString(actual_cstate);

	if(is_assert_true) {
      cerr << "                    TEST PASSED " << endl;
	} else {
		cerr << "                    TEST FAILED ****** " << endl;
	}

	return is_assert_true;

}

void Core::debugSetDramState(ADDRINT address, DramDirectoryEntry::dstate_t dstate, vector<UINT32> sharers_list)
{
	memory_manager->debugSetDramState(address, dstate, sharers_list);
}

bool Core::debugAssertDramState(ADDRINT address, DramDirectoryEntry::dstate_t dstate, vector<UINT32> sharers_list)
{
	return memory_manager->debugAssertDramState(address, dstate, sharers_list);

}

/*
void Core::setDramBoundaries(vector< pair<ADDRINT, ADDRINT> > addr_boundaries)
{
	cerr << "CORE: setting dram boundaries" << endl;
	assert( g_knob_simarch_has_shared_mem );
	memory_manager->setDramBoundaries(addr_boundaries);
	cerr << "CORE: finished setting dram boundaries" << endl;
}
*/
<|endoftext|>


<commit_before>#include <tabulate/table.hpp>
using namespace tabulate;

int main() {

  Table readme;

  readme.format()
    .border_color(Color::yellow)
    .font_style({FontStyle::bold});

  // Add rows
  Table highlights;

  highlights.add_row({"Header-only Library", "Requires C++17", "MIT License"});

  readme.add_row({"tabulate for Modern C++"});
  readme[0].format().font_align(FontAlign::center).font_style({FontStyle::bold}).font_color(Color::yellow);

  readme.add_row({"https://github.com/p-ranav/tabulate"});
  readme[1].format()
    .font_align(FontAlign::center)
    .font_style({FontStyle::underline, FontStyle::italic})
    .font_color(Color::white)
    .hide_border_top();

  readme.add_row({"Tabulate is a header-only library for printing aligned, formatted, and colorized tables in Modern C++"});
  readme[2].format().font_style({FontStyle::italic}).font_color(Color::magenta);

  readme.add_row({highlights});
  readme[3].format().font_align(FontAlign::center).hide_border_top();
  readme.add_row({"Easily format and align content within cells"});
  readme[4].format().font_align(FontAlign::center);

  Table format;
  format.add_row({"Horizontal Alignment", "Left aligned", "Center aligned", "Right aligned"});
  format[0][0].format().font_color(Color::green);
  format.column(1).format().width(25);
  format.column(2).format().width(25).font_align(FontAlign::center);
  format.column(3).format().width(25).font_align(FontAlign::right);

  format.add_row({"Automatic Word-Wrapping", "Long sentences automatically word-wrap based on the width of the column",
    "Word-wrapping also plays nicely with alignment rules. For instance, this cell is center aligned.",
    "You can also enforce \ncustom word-wrapping \nby embedding '\\n' \ncharacters in your cell\n content."});
  format[1][2].format().font_align(FontAlign::center);
  format[1][3].format().font_align(FontAlign::right);

  format.column(0).format().width(23);

  readme.add_row({format});

  readme[4].format()
    .font_color(Color::cyan)
    .font_style({FontStyle::underline, FontStyle::bold})
    .padding_top(0)
    .padding_bottom(0);

  readme[5].format()
    .hide_border_top()
    .padding_top(0);

  readme.add_row({"Colorize your tables\nWhat's red and smells like blue paint? ... Red paint!"});
  readme[6].format()
    .font_align(FontAlign::center)
    .border_color(Color::red)
    .corner_color(Color::red)
    .padding_bottom(1)
    .background_color(Color::red);

  readme.add_row({Table().add_row(
    {"You can \nalso embed...",
      Table().add_row(
        {"tables",
          Table().add_row(
            {"within tables",
              Table().add_row({"within tables",
                Table().add_row({"within tables.. and so on."})
              })})})})});

  readme[7].format()
    .border_left(":")
    .border_right(":")
    .hide_border_top()
    .font_color(Color::cyan);

  // Print the table
  std::cout << readme << std::endl;
}
<commit_msg>Minor update<commit_after>#include <tabulate/table.hpp>
using namespace tabulate;

int main() {

  Table readme;

  readme.format()
    .border_color(Color::yellow)
    .font_style({FontStyle::bold});

  // Add rows
  Table highlights;

  highlights.add_row({"Header-only Library", "Requires C++17", "MIT License"});

  readme.add_row({"tabulate for Modern C++"});
  readme[0].format().font_align(FontAlign::center).font_style({FontStyle::bold}).font_color(Color::yellow);

  readme.add_row({"https://github.com/p-ranav/tabulate"});
  readme[1].format()
    .font_align(FontAlign::center)
    .font_style({FontStyle::underline, FontStyle::italic})
    .font_color(Color::white)
    .hide_border_top();

  readme.add_row({"Tabulate is a header-only library for printing aligned, formatted, and colorized tables in Modern C++"});
  readme[2].format().font_style({FontStyle::italic}).font_color(Color::magenta);

  readme.add_row({highlights});
  readme[3].format().font_align(FontAlign::center).hide_border_top();
  readme.add_row({"Easily format and align content within cells"});
  readme[4].format().font_align(FontAlign::center);

  Table format;
  format.add_row({"Horizontal Alignment", "Left aligned", "Center aligned", "Right aligned"});
  format[0][0].format().font_color(Color::green);
  format.column(1).format().width(25);
  format.column(2).format().width(25).font_align(FontAlign::center);
  format.column(3).format().width(25).font_align(FontAlign::right);

  format.add_row({"Automatic Word-Wrapping", "Long sentences automatically word-wrap based on the width of the column",
    "Word-wrapping also plays nicely with alignment rules. For instance, this cell is center aligned.",
    "You can also enforce \ncustom word-wrapping \nby embedding '\\n' \ncharacters in your cell\n content."});
  format[1][2].format().font_align(FontAlign::center);
  format[1][3].format().font_align(FontAlign::right);

  format.column(0).format().width(23);

  readme.add_row({format});

  readme[4].format()
    .font_color(Color::cyan)
    .font_style({FontStyle::underline, FontStyle::bold})
    .padding_top(0)
    .padding_bottom(0);

  readme[5].format()
    .hide_border_top()
    .padding_top(0);

  readme.add_row({"Colorize cells, rows, or even entire tables\nWhat's red and smells like blue paint? ... Red paint!"});
  readme[6].format()
    .font_align(FontAlign::center)
    .border_color(Color::red)
    .corner_color(Color::red)
    .padding_bottom(1)
    .background_color(Color::red);

  Table embedded_table;
  embedded_table.add_row(
      {"You can \nalso embed...",
        Table().add_row(
          {"tables",
            Table().add_row(
              {"within tables",
                Table().add_row({"within tables",
                  Table().add_row({"within tables.. and so on."})
                })})})});
  embedded_table.format()
    .border_left("%")
    .border_right("%");

  embedded_table.column(1).format()
    .border_left("\\");

  readme.add_row({embedded_table});

  readme[7].format()
    .border_left(":")
    .border_right(":")
    .hide_border_top()
    .font_color(Color::cyan);

  // Print the table
  std::cout << readme << std::endl;
}
<|endoftext|>


<commit_before><commit_msg>Commit for tfarina<commit_after><|endoftext|>


<commit_before>/* -*- mode:c++; tab-width:4; c-basic-offset:4; -*-
 *
 * This file is part of maemo-security-certman
 *
 * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
 *
 * Contact: Juhani Mkel <ext-juhani.3.makela@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include "maemosec_common.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <linux/limits.h>
#include <dirent.h>
#include <regex.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

using namespace std;

extern "C" {

	#define DYNHEX_STRINGS 10
	int eh_registered = 0;
	int dynhexpos = 0;
	char* dynhexring[DYNHEX_STRINGS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

	static void clean_dynhexring(void)
	{
		int i;
		for (i = 0; i < DYNHEX_STRINGS; i++) {
			if (dynhexring[i])
				free(dynhexring[i]);
		}
		MAEMOSEC_DEBUG(1, "Exit application");
	}

	const char* dynhex(const unsigned char* d, unsigned len)
	{
		int i;
		char *t, *s = (char*)malloc(2*len + 1);

		if (NULL == s) {
			abort();
		}
		strcpy(s, "");
		for (t = s, i = 0; i < len; i++, t += 2) {
			sprintf(t, "%02x", *d++);
		}
		dynhexring[dynhexpos] = s;
		dynhexpos = (dynhexpos + 1) % DYNHEX_STRINGS;
		if (dynhexring[dynhexpos]) {
			free(dynhexring[dynhexpos]);
			dynhexring[dynhexpos] = NULL;
		}
		if (!eh_registered) {
			atexit(clean_dynhexring);
			eh_registered = 1;
		}
		return(s);
	}

	bool
	absolute_pathname(const char* pathname, string& to_this)
	{
		int rc, curdirh = -1;
		struct stat fs;
		string dirname;
		char cdirname [PATH_MAX];
		char* dirsep = NULL;
		bool is_local = false;
		char* tgtname = NULL;
		size_t rv;

		if ('\0' == *pathname)
			return(false);

		rc = lstat(pathname, &fs);
		if (rc == -1) {
			MAEMOSEC_ERROR("cannot stat '%s' (%d)", pathname, errno);
			return(false);
		}

		if (S_ISLNK(fs.st_mode)) {
			tgtname = (char*)malloc(PATH_MAX);
			if (!tgtname) {
				MAEMOSEC_ERROR("cannot allocate");
				goto fail;
			}
			rv = readlink(pathname, tgtname, PATH_MAX - 1);
			if (rv == -1) {
				MAEMOSEC_ERROR("cannot read link '%s' (%d)", pathname, errno);
				goto fail;
			} else {
				*(tgtname + rv) = '\0';
			}
			pathname = tgtname;
		}

		if (!S_ISDIR(fs.st_mode)) {
			dirsep = strrchr(pathname, '/');
			if (!dirsep) {
				dirname = ".";
				is_local = true;
			} else
				dirname.append(pathname, dirsep - pathname);
		} else
			dirname = pathname;

		if (!is_local) {
			// Take a handle to the current directory
			curdirh = open(".", O_RDONLY);
			if (curdirh == -1) {
				MAEMOSEC_ERROR("cannot open current directory (%d)", errno);
				goto fail;
			}

			// Change into the given directory
			rc = chdir(dirname.c_str());
			if (rc == -1) {
				MAEMOSEC_ERROR("cannot change into '%s' (%d)", dirname.c_str(), errno);
				goto fail;
			}
		}

		// Get the absolute pathname
		if (getcwd(cdirname, sizeof(cdirname)))
			MAEMOSEC_DEBUG(1, "current dir is '%s'", cdirname);
		else
			MAEMOSEC_ERROR("getcwd returned NULL (%s)", strerror(errno));

		to_this = cdirname;
		if (is_local) {
			to_this.append("/");
			to_this.append(pathname);
		} else if (dirsep) {
			to_this.append(dirsep);
		}

		if (!is_local) {
			// Change back to original working dir
			rc = fchdir(curdirh);
			if (rc == -1) {
				MAEMOSEC_ERROR("cannot change back (%d)", errno);
			}
			close(curdirh);
		}

		if (tgtname)
			free(tgtname);
		return(true);

	  fail:
		if (curdirh != -1) {
			if (-1 == fchdir(curdirh))
				MAEMOSEC_ERROR("Cannot cd back to original directory (%s)", strerror(errno));
			close(curdirh);
		}
		if (tgtname)
			free(tgtname);
		return(false);
	}

	bool
	process_name(string& to_this)
	{
		pid_t my_pid = getpid();
		char exe_name [PATH_MAX];

		sprintf(exe_name, "/proc/%ld/exe", (long)my_pid);
		absolute_pathname(exe_name, to_this);
		/*
		 * TODO: What follows is a somewhat ugly hack that should be
		 * replaced by a proper application id derived from integrity
		 * framework (i.e. package database and images hashes)
		 */
		if ("/usr/bin/maemo-launcher" == to_this) {
			int fd;
			char buf [PATH_MAX] = "";
			sprintf(exe_name, "/proc/%ld/cmdline", (long)my_pid);
			fd = open(exe_name, O_RDONLY);
			if (fd >= 0) {
				ssize_t len = read(fd, buf, sizeof(buf));
				if (len) {
					MAEMOSEC_DEBUG(1, "'%s': %ld '%s'", exe_name, len, buf);
					to_this = buf;
				}
				close(fd);
			}
		}
		return(true);
	}

	void
	append_hex(string& to_this, unsigned char* dta, unsigned len)
	{
		const unsigned locbuf_size = 128;
		char locbuf [locbuf_size + 1], *to;
		unsigned i, lim;

		lim = locbuf_size/2;
		while (len) {
			to = locbuf;
			if (lim > len)
				lim = len;
			for (i = 0; i < lim; i++) {
				sprintf(to, "%02x", *dta++);
				to += 2;
			}
			to_this.append(locbuf, i * 2);
			len -= lim;
		}
	}

	bool
	file_exists(const char* name)
	{
		int rc;
		struct stat fs;

		rc = stat(name, &fs);
		if (rc == -1) {
			MAEMOSEC_DEBUG(1, "cannot stat '%s' (%s)", name, strerror(errno));
			return(false);
		}
		if (S_ISREG(fs.st_mode))
			return(true);
		else
			return(false);
	}

	bool
	directory_exists(const char* name)
	{
		int rc;
		struct stat fs;

		rc = stat(name, &fs);
		if (rc == -1) {
			MAEMOSEC_DEBUG(1, "cannot stat '%s' (%s)", name, strerror(errno));
			return(false);
		}
		if (S_ISDIR(fs.st_mode))
			return(true);
		else
			return(false);
	}

	static int
	create_if_needed(const char* dir, int mode)
	{
		struct stat fs;
		int rc;

		MAEMOSEC_DEBUG(2, "Test '%s'", dir);
		rc = stat(dir, &fs);
		if (0 > rc) {
			if (errno == ENOENT) {
				MAEMOSEC_DEBUG(2, "Create '%s'", dir);
				rc = mkdir(dir, mode);
				if (0 > rc) {
					return(0);
				} else {
					MAEMOSEC_DEBUG(2, "Creation failed (%s)",
						       strerror(errno));
					return(errno);
				}
			} else {
				MAEMOSEC_DEBUG(2,
					       "Error other than ENOENT with '%s' (%s)",
					       dir, strerror(errno));
				return(errno);
			}
		} else {
			if (!S_ISDIR(fs.st_mode)) {
				MAEMOSEC_DEBUG(2, "overlapping non-directory");
				return(EEXIST);
			} else
				return(0);
		}
	}

	int
	create_directory(const char* path, int mode)
	{
		string locbuf;
		char* sep;
		struct stat fs;
		int rc;

		if (!path)
			return(ENOENT);

		locbuf.assign(path);
		sep = (char*)locbuf.c_str();
		sep++;

		while (sep && *sep) {
			sep = strchr(sep, *PATH_SEP);
			if (sep) {
				*sep = '\0';
				rc = create_if_needed(locbuf.c_str(), mode);
				if (0 != rc) {
					MAEMOSEC_ERROR("creation of '%s' failed (%s)",
						  locbuf.c_str(), strerror(errno));
					return(errno);
				}
				*sep = *PATH_SEP;
				sep++;
			}
		}
		rc = create_if_needed(path, mode);
		if (0 != rc) {
			MAEMOSEC_ERROR("creation of '%s' failed (%s)",
				  locbuf.c_str(), strerror(errno));
			return(rc);
		} else
			return(0);
	}

	int
	iterate_files(const char* in_directory,
				  const char* matching_names,
				  maemosec_callback* cb_func,
				  void* ctx)
	{
		DIR* dh;
		unsigned char dir_d_type = '\0';
		struct dirent* entry;
		int rc, res = 0, count = 0;
		regex_t name_pattern;
		char ebuf[100];

		if (!cb_func || !in_directory)
			return(0 - EINVAL);

		if (matching_names) {
			rc = regcomp(&name_pattern, matching_names, REG_NOSUB);
			if (0 != rc) {
				res = regerror(rc, &name_pattern, ebuf, sizeof(ebuf));
				MAEMOSEC_ERROR("'%s' invalid regex %s (%d)", matching_names, ebuf, res);
				regfree(&name_pattern);
				return(0 - EINVAL);
			}
		}

		dh = opendir(in_directory);
		if (NULL == dh) {
			MAEMOSEC_ERROR("cannot open '%s'", in_directory);
			return(0 - errno);
		}

		while (NULL != (entry = readdir(dh))) {
			/*
			 * The first entry should always be the reference to
			 * the directory itself. From that we get the d_type
			 * value for directories. Don't want to fix it, as
			 * man readdir says that it varies.
			 */
			MAEMOSEC_DEBUG(2, "%s:%s", __func__, entry->d_name);

			if (0 == strcmp(".", entry->d_name)
				|| 0 == strcmp("..", entry->d_name))
			{
				dir_d_type = entry->d_type;
				MAEMOSEC_DEBUG(2, "Directory type is '%hd'", dir_d_type);

			} else
#if 0
				if (entry->d_type != dir_d_type) {
#else
			{
#endif
				if (matching_names) {
					rc = regexec(&name_pattern, entry->d_name, 0, NULL, 0);
					MAEMOSEC_DEBUG(2, "'%s' %s '%s'",
								   entry->d_name,
								   rc?"!~":"~",
								   matching_names);
				} else
					rc = 0;
				if (0 == rc) {
					res = cb_func(count, entry->d_name, ctx);
					if (res)
						break;
					count++;
				}
			}
#if 0
			else {
				MAEMOSEC_DEBUG(2, "%s is directory (%hd)", entry->d_name, entry->d_type);
			}
#endif
		}
		closedir(dh);
		if (matching_names)
			regfree(&name_pattern);
		return(res);
	}

}
<commit_msg>Fixed error handling in directory creation; which bug was introduced by a careless fix in commit c7ff51ba... (fixed coverity findings).<commit_after>/* -*- mode:c++; tab-width:4; c-basic-offset:4; -*-
 *
 * This file is part of maemo-security-certman
 *
 * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
 *
 * Contact: Juhani Mkel <ext-juhani.3.makela@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include "maemosec_common.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <linux/limits.h>
#include <dirent.h>
#include <regex.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

using namespace std;

extern "C" {

	#define DYNHEX_STRINGS 10
	int eh_registered = 0;
	int dynhexpos = 0;
	char* dynhexring[DYNHEX_STRINGS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

	static void clean_dynhexring(void)
	{
		int i;
		for (i = 0; i < DYNHEX_STRINGS; i++) {
			if (dynhexring[i])
				free(dynhexring[i]);
		}
		MAEMOSEC_DEBUG(1, "Exit application");
	}

	const char* dynhex(const unsigned char* d, unsigned len)
	{
		int i;
		char *t, *s = (char*)malloc(2*len + 1);

		if (NULL == s) {
			abort();
		}
		strcpy(s, "");
		for (t = s, i = 0; i < len; i++, t += 2) {
			sprintf(t, "%02x", *d++);
		}
		dynhexring[dynhexpos] = s;
		dynhexpos = (dynhexpos + 1) % DYNHEX_STRINGS;
		if (dynhexring[dynhexpos]) {
			free(dynhexring[dynhexpos]);
			dynhexring[dynhexpos] = NULL;
		}
		if (!eh_registered) {
			atexit(clean_dynhexring);
			eh_registered = 1;
		}
		return(s);
	}

	bool
	absolute_pathname(const char* pathname, string& to_this)
	{
		int rc, curdirh = -1;
		struct stat fs;
		string dirname;
		char cdirname [PATH_MAX];
		char* dirsep = NULL;
		bool is_local = false;
		char* tgtname = NULL;
		size_t rv;

		if ('\0' == *pathname)
			return(false);

		rc = lstat(pathname, &fs);
		if (rc == -1) {
			MAEMOSEC_ERROR("cannot stat '%s' (%d)", pathname, errno);
			return(false);
		}

		if (S_ISLNK(fs.st_mode)) {
			tgtname = (char*)malloc(PATH_MAX);
			if (!tgtname) {
				MAEMOSEC_ERROR("cannot allocate");
				goto fail;
			}
			rv = readlink(pathname, tgtname, PATH_MAX - 1);
			if (rv == -1) {
				MAEMOSEC_ERROR("cannot read link '%s' (%d)", pathname, errno);
				goto fail;
			} else {
				*(tgtname + rv) = '\0';
			}
			pathname = tgtname;
		}

		if (!S_ISDIR(fs.st_mode)) {
			dirsep = strrchr(pathname, '/');
			if (!dirsep) {
				dirname = ".";
				is_local = true;
			} else
				dirname.append(pathname, dirsep - pathname);
		} else
			dirname = pathname;

		if (!is_local) {
			// Take a handle to the current directory
			curdirh = open(".", O_RDONLY);
			if (curdirh == -1) {
				MAEMOSEC_ERROR("cannot open current directory (%d)", errno);
				goto fail;
			}

			// Change into the given directory
			rc = chdir(dirname.c_str());
			if (rc == -1) {
				MAEMOSEC_ERROR("cannot change into '%s' (%d)", dirname.c_str(), errno);
				goto fail;
			}
		}

		// Get the absolute pathname
		if (getcwd(cdirname, sizeof(cdirname)))
			MAEMOSEC_DEBUG(1, "current dir is '%s'", cdirname);
		else
			MAEMOSEC_ERROR("getcwd returned NULL (%s)", strerror(errno));

		to_this = cdirname;
		if (is_local) {
			to_this.append("/");
			to_this.append(pathname);
		} else if (dirsep) {
			to_this.append(dirsep);
		}

		if (!is_local) {
			// Change back to original working dir
			rc = fchdir(curdirh);
			if (rc == -1) {
				MAEMOSEC_ERROR("cannot change back (%d)", errno);
			}
			close(curdirh);
		}

		if (tgtname)
			free(tgtname);
		return(true);

	  fail:
		if (curdirh != -1) {
			if (-1 == fchdir(curdirh))
				MAEMOSEC_ERROR("Cannot cd back to original directory (%s)", strerror(errno));
			close(curdirh);
		}
		if (tgtname)
			free(tgtname);
		return(false);
	}

	bool
	process_name(string& to_this)
	{
		pid_t my_pid = getpid();
		char exe_name [PATH_MAX];

		sprintf(exe_name, "/proc/%ld/exe", (long)my_pid);
		absolute_pathname(exe_name, to_this);
		/*
		 * TODO: What follows is a somewhat ugly hack that should be
		 * replaced by a proper application id derived from integrity
		 * framework (i.e. package database and images hashes)
		 */
		if ("/usr/bin/maemo-launcher" == to_this) {
			int fd;
			char buf [PATH_MAX] = "";
			sprintf(exe_name, "/proc/%ld/cmdline", (long)my_pid);
			fd = open(exe_name, O_RDONLY);
			if (fd >= 0) {
				ssize_t len = read(fd, buf, sizeof(buf));
				if (len) {
					MAEMOSEC_DEBUG(1, "'%s': %ld '%s'", exe_name, len, buf);
					to_this = buf;
				}
				close(fd);
			}
		}
		return(true);
	}

	void
	append_hex(string& to_this, unsigned char* dta, unsigned len)
	{
		const unsigned locbuf_size = 128;
		char locbuf [locbuf_size + 1], *to;
		unsigned i, lim;

		lim = locbuf_size/2;
		while (len) {
			to = locbuf;
			if (lim > len)
				lim = len;
			for (i = 0; i < lim; i++) {
				sprintf(to, "%02x", *dta++);
				to += 2;
			}
			to_this.append(locbuf, i * 2);
			len -= lim;
		}
	}

	bool
	file_exists(const char* name)
	{
		int rc;
		struct stat fs;

		rc = stat(name, &fs);
		if (rc == -1) {
			MAEMOSEC_DEBUG(1, "cannot stat '%s' (%s)", name, strerror(errno));
			return(false);
		}
		if (S_ISREG(fs.st_mode))
			return(true);
		else
			return(false);
	}

	bool
	directory_exists(const char* name)
	{
		int rc;
		struct stat fs;

		rc = stat(name, &fs);
		if (rc == -1) {
			MAEMOSEC_DEBUG(1, "cannot stat '%s' (%s)", name, strerror(errno));
			return(false);
		}
		if (S_ISDIR(fs.st_mode))
			return(true);
		else
			return(false);
	}

	static int
	create_if_needed(const char* dir, int mode)
	{
		struct stat fs;
		int rc;

		MAEMOSEC_DEBUG(2, "Test '%s'", dir);
		rc = stat(dir, &fs);
		if (0 > rc) {
			if (errno == ENOENT) {
				MAEMOSEC_DEBUG(2, "Create '%s'", dir);
				rc = mkdir(dir, mode);
				if (0 == rc) {
					return(0);
				} else {
					MAEMOSEC_DEBUG(2, "Creation failed (%s)",
						       strerror(errno));
					return(errno);
				}
			} else {
				MAEMOSEC_DEBUG(2,
					       "Error other than ENOENT with '%s' (%s)",
					       dir, strerror(errno));
				return(errno);
			}
		} else {
			if (!S_ISDIR(fs.st_mode)) {
				MAEMOSEC_DEBUG(2, "overlapping non-directory");
				return(EEXIST);
			} else
				return(0);
		}
	}

	int
	create_directory(const char* path, int mode)
	{
		string locbuf;
		char* sep;
		struct stat fs;
		int rc;

		if (!path)
			return(ENOENT);

		locbuf.assign(path);
		sep = (char*)locbuf.c_str();
		sep++;

		while (sep && *sep) {
			sep = strchr(sep, *PATH_SEP);
			if (sep) {
				*sep = '\0';
				rc = create_if_needed(locbuf.c_str(), mode);
				if (0 != rc) {
					MAEMOSEC_ERROR("creation of '%s' failed (%s)",
						  locbuf.c_str(), strerror(errno));
					return(errno);
				}
				*sep = *PATH_SEP;
				sep++;
			}
		}
		rc = create_if_needed(path, mode);
		if (0 != rc) {
			MAEMOSEC_ERROR("creation of '%s' failed (%s)",
				  locbuf.c_str(), strerror(errno));
			return(rc);
		} else
			return(0);
	}

	int
	iterate_files(const char* in_directory,
				  const char* matching_names,
				  maemosec_callback* cb_func,
				  void* ctx)
	{
		DIR* dh;
		unsigned char dir_d_type = '\0';
		struct dirent* entry;
		int rc, res = 0, count = 0;
		regex_t name_pattern;
		char ebuf[100];

		if (!cb_func || !in_directory)
			return(0 - EINVAL);

		if (matching_names) {
			rc = regcomp(&name_pattern, matching_names, REG_NOSUB);
			if (0 != rc) {
				res = regerror(rc, &name_pattern, ebuf, sizeof(ebuf));
				MAEMOSEC_ERROR("'%s' invalid regex %s (%d)", matching_names, ebuf, res);
				regfree(&name_pattern);
				return(0 - EINVAL);
			}
		}

		dh = opendir(in_directory);
		if (NULL == dh) {
			MAEMOSEC_ERROR("cannot open '%s'", in_directory);
			return(0 - errno);
		}

		while (NULL != (entry = readdir(dh))) {
			/*
			 * The first entry should always be the reference to
			 * the directory itself. From that we get the d_type
			 * value for directories. Don't want to fix it, as
			 * man readdir says that it varies.
			 */
			MAEMOSEC_DEBUG(2, "%s:%s", __func__, entry->d_name);

			if (0 == strcmp(".", entry->d_name)
				|| 0 == strcmp("..", entry->d_name))
			{
				dir_d_type = entry->d_type;
				MAEMOSEC_DEBUG(2, "Directory type is '%hd'", dir_d_type);

			} else
#if 0
				if (entry->d_type != dir_d_type) {
#else
			{
#endif
				if (matching_names) {
					rc = regexec(&name_pattern, entry->d_name, 0, NULL, 0);
					MAEMOSEC_DEBUG(2, "'%s' %s '%s'",
								   entry->d_name,
								   rc?"!~":"~",
								   matching_names);
				} else
					rc = 0;
				if (0 == rc) {
					res = cb_func(count, entry->d_name, ctx);
					if (res)
						break;
					count++;
				}
			}
#if 0
			else {
				MAEMOSEC_DEBUG(2, "%s is directory (%hd)", entry->d_name, entry->d_type);
			}
#endif
		}
		closedir(dh);
		if (matching_names)
			regfree(&name_pattern);
		return(res);
	}

}
<|endoftext|>


<commit_before>/* Gobby - GTK-based collaborative text editor
 * Copyright (C) 2008-2014 Armin Burgmeier <armin@arbur.net>
 *
 * 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 2 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, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

#include "commands/browser-commands.hpp"
#include "util/i18n.hpp"

#include <libinfinity/common/inf-request-result.h>

class Gobby::BrowserCommands::BrowserInfo
{
public:
	BrowserInfo(BrowserCommands& commands,
	            InfBrowser* browser);

	~BrowserInfo();

	InfBrowser* get_browser() { return m_browser; }
private:
	static void on_notify_status_static(GObject* object,
	                                    GParamSpec* pspec,
	                                    gpointer user_data)
	{
		static_cast<BrowserCommands*>(user_data)->on_notify_status(
			INF_BROWSER(object));
	}

	InfBrowser* m_browser;

	gulong m_notify_status_handler;
};

class Gobby::BrowserCommands::RequestInfo
{
	friend class BrowserCommands;
public:
	RequestInfo(BrowserCommands& commands,
	            InfBrowser* browser, InfBrowserIter* iter,
	            StatusBar& status_bar);
	~RequestInfo();

	InfBrowser* get_browser() { return m_browser; }

	void set_request(InfRequest* request);
private:
	static void on_node_finished_static(InfRequest* request,
	                                    const InfRequestResult* result,
	                                    const GError* error,
	                                    gpointer user_data)
	{
		const InfBrowserIter* iter;
		inf_request_result_get_subscribe_session(
			result, NULL, &iter, NULL);
		RequestInfo* info = static_cast<RequestInfo*>(user_data);

		g_assert(iter == NULL || iter->node == info->m_iter.node);
		g_assert(iter == NULL ||
		         iter->node_id == info->m_iter.node_id);

		info->m_commands.on_finished(
			INF_REQUEST(request),
			info->m_browser, iter, error);
	}

	static void on_chat_finished_static(InfRequest* request,
	                                    const InfRequestResult* result,
	                                    const GError* error,
	                                    gpointer user_data)
	{
		RequestInfo* info = static_cast<RequestInfo*>(user_data);

		info->m_commands.on_finished(
			INF_REQUEST(request), info->m_browser, NULL, error);
	}

	BrowserCommands& m_commands;
	InfBrowser* m_browser;
	InfBrowserIter m_iter;

	StatusBar& m_status_bar;
	StatusBar::MessageHandle m_handle;

	InfRequest* m_request;
	gulong m_finished_handler;
};

Gobby::BrowserCommands::BrowserInfo::BrowserInfo(BrowserCommands& cmds,
                                                 InfBrowser* browser):
	m_browser(browser)
{
	m_notify_status_handler = g_signal_connect(
		m_browser, "notify::status",
		G_CALLBACK(on_notify_status_static), &cmds);

	g_object_ref(browser);
}

Gobby::BrowserCommands::BrowserInfo::~BrowserInfo()
{
	g_signal_handler_disconnect(m_browser, m_notify_status_handler);

	g_object_unref(m_browser);
}

Gobby::BrowserCommands::RequestInfo::RequestInfo(BrowserCommands& commands,
                                                 InfBrowser* browser,
                                                 InfBrowserIter* iter,
                                                 StatusBar& status_bar):
	m_commands(commands), m_browser(browser), m_status_bar(status_bar),
	m_request(NULL), m_finished_handler(0)
{
	if(iter)
	{
		m_iter = *iter;

		m_handle = m_status_bar.add_info_message(
			Glib::ustring::compose(
				_("Subscribing to %1..."), Glib::ustring(
					inf_browser_get_node_name(
						browser, iter))));
	}
	else
	{
		InfXmlConnection* connection =
			infc_browser_get_connection(INFC_BROWSER(browser));
		gchar* remote_hostname;
		g_object_get(G_OBJECT(connection),
		             "remote-hostname", &remote_hostname, NULL);
		m_handle = m_status_bar.add_info_message(
			Glib::ustring::compose(
				_("Subscribing to chat on %1..."),
					remote_hostname));
		g_free(remote_hostname);
	}
}

Gobby::BrowserCommands::RequestInfo::~RequestInfo()
{
	m_status_bar.remove_message(m_handle);

	if(m_request != NULL)
	{
		g_signal_handler_disconnect(m_request, m_finished_handler);
		g_object_unref(m_request);
	}
}

void Gobby::BrowserCommands::RequestInfo::set_request(InfRequest* request)
{
	g_assert(m_request == NULL);

	m_finished_handler = g_signal_handler_find(
		request, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, this);
	g_assert(m_finished_handler != 0);
}

Gobby::BrowserCommands::BrowserCommands(Browser& browser,
                                        FolderManager& folder_manager,
                                        StatusBar& status_bar,
                                        Operations& operations):
	m_browser(browser), m_folder_manager(folder_manager),
	m_operations(operations), m_status_bar(status_bar)
{
	m_browser.signal_connect().connect(
		sigc::mem_fun(*this, &BrowserCommands::on_connect));
	m_browser.signal_activate().connect(
		sigc::mem_fun(*this, &BrowserCommands::on_activate));

	m_set_browser_handler = g_signal_connect(
		browser.get_store(), "set-browser",
		G_CALLBACK(on_set_browser_static), this);
}

Gobby::BrowserCommands::~BrowserCommands()
{
	for(RequestMap::iterator iter = m_request_map.begin();
	    iter != m_request_map.end(); ++ iter)
	{
		delete iter->second;
	}

	for(BrowserMap::iterator iter = m_browser_map.begin();
	    iter != m_browser_map.end(); ++iter)
	{
		delete iter->second;
	}

	g_signal_handler_disconnect(m_browser.get_store(),
	                            m_set_browser_handler);
}

void Gobby::BrowserCommands::on_set_browser(InfGtkBrowserModel* model,
                                            GtkTreeIter* iter,
                                            InfBrowser* old_browser,
                                            InfBrowser* new_browser)
{
	if(old_browser != NULL)
	{
		// Find by browser in case old_browser has its connection
		// reset.
		BrowserMap::iterator iter = m_browser_map.find(old_browser);

		g_assert(iter != m_browser_map.end());

		delete iter->second;
		m_browser_map.erase(iter);
	}

	if(new_browser != NULL)
	{
		g_assert(m_browser_map.find(new_browser) ==
		         m_browser_map.end());

		InfBrowserStatus browser_status;
		g_object_get(
			G_OBJECT(new_browser), "status",
			&browser_status, NULL);

		m_browser_map[new_browser] =
			new BrowserInfo(*this, new_browser);
		if(browser_status == INF_BROWSER_OPEN)
		{
			if(INFC_IS_BROWSER(new_browser))
			{
				InfcBrowser* infcbrowser =
					INFC_BROWSER(new_browser);
				InfcSessionProxy* proxy =
					infc_browser_get_chat_session(
						infcbrowser);
				if(!proxy)
					subscribe_chat(infcbrowser);
			}
		}
	}
}

void Gobby::BrowserCommands::on_notify_status(InfBrowser* browser)
{
	InfXmlConnection* connection;
	InfXmlConnectionStatus status;
	InfBrowserStatus browser_status;

	g_object_get(G_OBJECT(browser), "status", &browser_status, NULL);
	switch(browser_status)
	{
	case INF_BROWSER_CLOSED:
		// Close connection if browser got disconnected. This for
		// example happens when the server does not send an initial
		// welcome message.
		connection =
			infc_browser_get_connection(INFC_BROWSER(browser));
		g_object_get(G_OBJECT(connection), "status", &status, NULL);
		if(status != INF_XML_CONNECTION_CLOSED &&
		   status != INF_XML_CONNECTION_CLOSING)
		{
			inf_xml_connection_close(connection);
		}

		break;
	case INF_BROWSER_OPENING:
		break;
	case INF_BROWSER_OPEN:
		if(!infc_browser_get_chat_session(INFC_BROWSER(browser)))
			subscribe_chat(INFC_BROWSER(browser));
		break;
	default:
		g_assert_not_reached();
		break;
	}
}

void Gobby::BrowserCommands::subscribe_chat(InfcBrowser* browser)
{
	std::auto_ptr<RequestInfo> info(new RequestInfo(
		*this, INF_BROWSER(browser), NULL, m_status_bar));

	InfRequest* request = INF_REQUEST(
		infc_browser_subscribe_chat(
			browser,
			RequestInfo::on_chat_finished_static, info.get()));

	if(request != NULL)
	{
		info->set_request(request);
		g_assert(m_request_map.find(request) == m_request_map.end());
		m_request_map[request] = info.release();
	}
}

void Gobby::BrowserCommands::on_connect(const Glib::ustring& hostname)
{
	m_operations.subscribe_path(hostname);
}

void Gobby::BrowserCommands::on_activate(InfBrowser* browser,
                                         InfBrowserIter* iter)
{
	InfSessionProxy* proxy = inf_browser_get_session(browser, iter);

	if(proxy != NULL)
	{
		InfSession* session;
		g_object_get(G_OBJECT(proxy), "session", &session, NULL);
		SessionView* view = m_folder_manager.lookup_document(session);
		g_object_unref(session);

		if(view != NULL)
		{
			m_folder_manager.switch_to_document(*view);
		}
		else
		{
			m_folder_manager.add_document(browser, iter, proxy);
		}
	}
	else
	{
		InfRequest* request =
			inf_browser_get_pending_request(
				browser, iter, "subscribe-session");

		// If there is already a request don't re-request
		if(request == NULL)
		{
			std::auto_ptr<RequestInfo> info(new RequestInfo(
				*this, browser, iter, m_status_bar));

			request = INF_REQUEST(
				inf_browser_subscribe(
					browser, iter,
					RequestInfo::on_node_finished_static,
					info.get()));

			if(request != NULL)
			{
				info->set_request(request);
				g_assert(m_request_map.find(request) ==
				         m_request_map.end());
				m_request_map[request] = info.release();
			}
		}
	}
}

void Gobby::BrowserCommands::on_finished(InfRequest* request,
                                         InfBrowser* browser,
                                         const InfBrowserIter* iter,
                                         const GError* error)
{
	RequestMap::iterator map_iter = m_request_map.find(request);
	if(map_iter != m_request_map.end())
	{
		delete map_iter->second;
		m_request_map.erase(map_iter);
	}

	if(error != NULL)
	{
		m_status_bar.add_error_message(
			_("Subscription failed"),
			error->message);
	}
	else if(iter != NULL)
	{
		InfSessionProxy* proxy =
			inf_browser_get_session(browser, iter);
		g_assert(proxy != NULL);

		m_folder_manager.add_document(browser, iter, proxy);
	}
	else
	{
		if(INFC_IS_BROWSER(browser))
		{
			InfSessionProxy* proxy = INF_SESSION_PROXY(
				infc_browser_get_chat_session(
					INFC_BROWSER(browser)));
			g_assert(proxy != NULL);

			m_folder_manager.add_document(browser, NULL, proxy);
		}
	}
}
<commit_msg>Fix an assertion failure when a subscription fails<commit_after>/* Gobby - GTK-based collaborative text editor
 * Copyright (C) 2008-2014 Armin Burgmeier <armin@arbur.net>
 *
 * 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 2 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, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

#include "commands/browser-commands.hpp"
#include "util/i18n.hpp"

#include <libinfinity/common/inf-request-result.h>

class Gobby::BrowserCommands::BrowserInfo
{
public:
	BrowserInfo(BrowserCommands& commands,
	            InfBrowser* browser);

	~BrowserInfo();

	InfBrowser* get_browser() { return m_browser; }
private:
	static void on_notify_status_static(GObject* object,
	                                    GParamSpec* pspec,
	                                    gpointer user_data)
	{
		static_cast<BrowserCommands*>(user_data)->on_notify_status(
			INF_BROWSER(object));
	}

	InfBrowser* m_browser;

	gulong m_notify_status_handler;
};

class Gobby::BrowserCommands::RequestInfo
{
	friend class BrowserCommands;
public:
	RequestInfo(BrowserCommands& commands,
	            InfBrowser* browser, InfBrowserIter* iter,
	            StatusBar& status_bar);
	~RequestInfo();

	InfBrowser* get_browser() { return m_browser; }

	void set_request(InfRequest* request);
private:
	static void on_node_finished_static(InfRequest* request,
	                                    const InfRequestResult* result,
	                                    const GError* error,
	                                    gpointer user_data)
	{
		const InfBrowserIter* iter = NULL;
		RequestInfo* info = static_cast<RequestInfo*>(user_data);

		if(error == NULL)
		{
			inf_request_result_get_subscribe_session(
				result, NULL, &iter, NULL);

			g_assert(iter == NULL ||
			         iter->node == info->m_iter.node);
			g_assert(iter == NULL ||
		        	 iter->node_id == info->m_iter.node_id);
		}

		info->m_commands.on_finished(
			INF_REQUEST(request),
			info->m_browser, iter, error);
	}

	static void on_chat_finished_static(InfRequest* request,
	                                    const InfRequestResult* result,
	                                    const GError* error,
	                                    gpointer user_data)
	{
		RequestInfo* info = static_cast<RequestInfo*>(user_data);

		info->m_commands.on_finished(
			INF_REQUEST(request), info->m_browser, NULL, error);
	}

	BrowserCommands& m_commands;
	InfBrowser* m_browser;
	InfBrowserIter m_iter;

	StatusBar& m_status_bar;
	StatusBar::MessageHandle m_handle;

	InfRequest* m_request;
	gulong m_finished_handler;
};

Gobby::BrowserCommands::BrowserInfo::BrowserInfo(BrowserCommands& cmds,
                                                 InfBrowser* browser):
	m_browser(browser)
{
	m_notify_status_handler = g_signal_connect(
		m_browser, "notify::status",
		G_CALLBACK(on_notify_status_static), &cmds);

	g_object_ref(browser);
}

Gobby::BrowserCommands::BrowserInfo::~BrowserInfo()
{
	g_signal_handler_disconnect(m_browser, m_notify_status_handler);

	g_object_unref(m_browser);
}

Gobby::BrowserCommands::RequestInfo::RequestInfo(BrowserCommands& commands,
                                                 InfBrowser* browser,
                                                 InfBrowserIter* iter,
                                                 StatusBar& status_bar):
	m_commands(commands), m_browser(browser), m_status_bar(status_bar),
	m_request(NULL), m_finished_handler(0)
{
	if(iter)
	{
		m_iter = *iter;

		m_handle = m_status_bar.add_info_message(
			Glib::ustring::compose(
				_("Subscribing to %1..."), Glib::ustring(
					inf_browser_get_node_name(
						browser, iter))));
	}
	else
	{
		InfXmlConnection* connection =
			infc_browser_get_connection(INFC_BROWSER(browser));
		gchar* remote_hostname;
		g_object_get(G_OBJECT(connection),
		             "remote-hostname", &remote_hostname, NULL);
		m_handle = m_status_bar.add_info_message(
			Glib::ustring::compose(
				_("Subscribing to chat on %1..."),
					remote_hostname));
		g_free(remote_hostname);
	}
}

Gobby::BrowserCommands::RequestInfo::~RequestInfo()
{
	m_status_bar.remove_message(m_handle);

	if(m_request != NULL)
	{
		g_signal_handler_disconnect(m_request, m_finished_handler);
		g_object_unref(m_request);
	}
}

void Gobby::BrowserCommands::RequestInfo::set_request(InfRequest* request)
{
	g_assert(m_request == NULL);

	m_finished_handler = g_signal_handler_find(
		request, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, this);
	g_assert(m_finished_handler != 0);
}

Gobby::BrowserCommands::BrowserCommands(Browser& browser,
                                        FolderManager& folder_manager,
                                        StatusBar& status_bar,
                                        Operations& operations):
	m_browser(browser), m_folder_manager(folder_manager),
	m_operations(operations), m_status_bar(status_bar)
{
	m_browser.signal_connect().connect(
		sigc::mem_fun(*this, &BrowserCommands::on_connect));
	m_browser.signal_activate().connect(
		sigc::mem_fun(*this, &BrowserCommands::on_activate));

	m_set_browser_handler = g_signal_connect(
		browser.get_store(), "set-browser",
		G_CALLBACK(on_set_browser_static), this);
}

Gobby::BrowserCommands::~BrowserCommands()
{
	for(RequestMap::iterator iter = m_request_map.begin();
	    iter != m_request_map.end(); ++ iter)
	{
		delete iter->second;
	}

	for(BrowserMap::iterator iter = m_browser_map.begin();
	    iter != m_browser_map.end(); ++iter)
	{
		delete iter->second;
	}

	g_signal_handler_disconnect(m_browser.get_store(),
	                            m_set_browser_handler);
}

void Gobby::BrowserCommands::on_set_browser(InfGtkBrowserModel* model,
                                            GtkTreeIter* iter,
                                            InfBrowser* old_browser,
                                            InfBrowser* new_browser)
{
	if(old_browser != NULL)
	{
		// Find by browser in case old_browser has its connection
		// reset.
		BrowserMap::iterator iter = m_browser_map.find(old_browser);

		g_assert(iter != m_browser_map.end());

		delete iter->second;
		m_browser_map.erase(iter);
	}

	if(new_browser != NULL)
	{
		g_assert(m_browser_map.find(new_browser) ==
		         m_browser_map.end());

		InfBrowserStatus browser_status;
		g_object_get(
			G_OBJECT(new_browser), "status",
			&browser_status, NULL);

		m_browser_map[new_browser] =
			new BrowserInfo(*this, new_browser);
		if(browser_status == INF_BROWSER_OPEN)
		{
			if(INFC_IS_BROWSER(new_browser))
			{
				InfcBrowser* infcbrowser =
					INFC_BROWSER(new_browser);
				InfcSessionProxy* proxy =
					infc_browser_get_chat_session(
						infcbrowser);
				if(!proxy)
					subscribe_chat(infcbrowser);
			}
		}
	}
}

void Gobby::BrowserCommands::on_notify_status(InfBrowser* browser)
{
	InfXmlConnection* connection;
	InfXmlConnectionStatus status;
	InfBrowserStatus browser_status;

	g_object_get(G_OBJECT(browser), "status", &browser_status, NULL);
	switch(browser_status)
	{
	case INF_BROWSER_CLOSED:
		// Close connection if browser got disconnected. This for
		// example happens when the server does not send an initial
		// welcome message.
		connection =
			infc_browser_get_connection(INFC_BROWSER(browser));
		g_object_get(G_OBJECT(connection), "status", &status, NULL);
		if(status != INF_XML_CONNECTION_CLOSED &&
		   status != INF_XML_CONNECTION_CLOSING)
		{
			inf_xml_connection_close(connection);
		}

		break;
	case INF_BROWSER_OPENING:
		break;
	case INF_BROWSER_OPEN:
		if(!infc_browser_get_chat_session(INFC_BROWSER(browser)))
			subscribe_chat(INFC_BROWSER(browser));
		break;
	default:
		g_assert_not_reached();
		break;
	}
}

void Gobby::BrowserCommands::subscribe_chat(InfcBrowser* browser)
{
	std::auto_ptr<RequestInfo> info(new RequestInfo(
		*this, INF_BROWSER(browser), NULL, m_status_bar));

	InfRequest* request = INF_REQUEST(
		infc_browser_subscribe_chat(
			browser,
			RequestInfo::on_chat_finished_static, info.get()));

	if(request != NULL)
	{
		info->set_request(request);
		g_assert(m_request_map.find(request) == m_request_map.end());
		m_request_map[request] = info.release();
	}
}

void Gobby::BrowserCommands::on_connect(const Glib::ustring& hostname)
{
	m_operations.subscribe_path(hostname);
}

void Gobby::BrowserCommands::on_activate(InfBrowser* browser,
                                         InfBrowserIter* iter)
{
	InfSessionProxy* proxy = inf_browser_get_session(browser, iter);

	if(proxy != NULL)
	{
		InfSession* session;
		g_object_get(G_OBJECT(proxy), "session", &session, NULL);
		SessionView* view = m_folder_manager.lookup_document(session);
		g_object_unref(session);

		if(view != NULL)
		{
			m_folder_manager.switch_to_document(*view);
		}
		else
		{
			m_folder_manager.add_document(browser, iter, proxy);
		}
	}
	else
	{
		InfRequest* request =
			inf_browser_get_pending_request(
				browser, iter, "subscribe-session");

		// If there is already a request don't re-request
		if(request == NULL)
		{
			std::auto_ptr<RequestInfo> info(new RequestInfo(
				*this, browser, iter, m_status_bar));

			request = INF_REQUEST(
				inf_browser_subscribe(
					browser, iter,
					RequestInfo::on_node_finished_static,
					info.get()));

			if(request != NULL)
			{
				info->set_request(request);
				g_assert(m_request_map.find(request) ==
				         m_request_map.end());
				m_request_map[request] = info.release();
			}
		}
	}
}

void Gobby::BrowserCommands::on_finished(InfRequest* request,
                                         InfBrowser* browser,
                                         const InfBrowserIter* iter,
                                         const GError* error)
{
	RequestMap::iterator map_iter = m_request_map.find(request);
	if(map_iter != m_request_map.end())
	{
		delete map_iter->second;
		m_request_map.erase(map_iter);
	}

	if(error != NULL)
	{
		m_status_bar.add_error_message(
			_("Subscription failed"),
			error->message);
	}
	else if(iter != NULL)
	{
		InfSessionProxy* proxy =
			inf_browser_get_session(browser, iter);
		g_assert(proxy != NULL);

		m_folder_manager.add_document(browser, iter, proxy);
	}
	else
	{
		if(INFC_IS_BROWSER(browser))
		{
			InfSessionProxy* proxy = INF_SESSION_PROXY(
				infc_browser_get_chat_session(
					INFC_BROWSER(browser)));
			g_assert(proxy != NULL);

			m_folder_manager.add_document(browser, NULL, proxy);
		}
	}
}
<|endoftext|>


<commit_before>#include <vector>
#include <string>
#include <sstream>

#include "error_handling.h"
#include "io.h"
#include "pack.h"
#include "level.h"
#include "misc.h"
#include "player.h"
#include "monster.h"
#include "colors.h"
#include "os.h"
#include "rogue.h"
#include "item.h"
#include "game.h"

#include "potions.h"

using namespace std;

std::vector<std::string>*        Potion::guesses;
std::vector<bool>*               Potion::knowledge;
std::vector<std::string const*>* Potion::colors;

static Potion::Type random_potion_type() {
  int value = os_rand_range(100);

  int end = static_cast<int>(Potion::Type::NPOTIONS);
  for (int i = 0; i < end; ++i) {
    Potion::Type type = static_cast<Potion::Type>(i);
    int probability = Potion::probability(type);

    if (value < probability) {
      return type;

    } else {
      value -= probability;
    }
  }

  error("Error! Sum of probabilities is not 100%");
}

Potion* Potion::clone() const {
  return new Potion(*this);
}

bool Potion::is_magic() const {
  return true;
}

string Potion::name(Potion::Type subtype) {
  switch(subtype) {
    case CONFUSION: return "confusion";
    case LSD:       return "hallucination";
    case POISON:    return "poison";
    case STRENGTH:  return "gain strength";
    case SEEINVIS:  return "see invisible";
    case HEALING:   return "healing";
    case MFIND:     return "monster detection";
    case TFIND:     return "magic detection";
    case RAISE:     return "raise level";
    case XHEAL:     return "extra healing";
    case HASTE:     return "haste self";
    case RESTORE:   return "restore strength";
    case BLIND:     return "blindness";
    case LEVIT:     return "levitation";
    case NPOTIONS:  error("Unknown subtype NPOTIONS");
  }
}

int Potion::probability(Potion::Type subtype) {
  switch(subtype) {
    case CONFUSION: return 7;
    case LSD:       return 8;
    case POISON:    return 8;
    case STRENGTH:  return 13;
    case SEEINVIS:  return 3;
    case HEALING:   return 13;
    case MFIND:     return 6;
    case TFIND:     return 6;
    case RAISE:     return 2;
    case XHEAL:     return 5;
    case HASTE:     return 5;
    case RESTORE:   return 13;
    case BLIND:     return 5;
    case LEVIT:     return 6;
    case NPOTIONS:  error("Unknown subtype NPOTIONS");
  }
}

int Potion::worth(Potion::Type subtype) {
  switch(subtype) {
    case CONFUSION: return 5;
    case LSD:       return 5;
    case POISON:    return 5;
    case STRENGTH:  return 150;
    case SEEINVIS:  return 100;
    case HEALING:   return 130;
    case MFIND:     return 130;
    case TFIND:     return 105;
    case RAISE:     return 250;
    case XHEAL:     return 200;
    case HASTE:     return 190;
    case RESTORE:   return 130;
    case BLIND:     return 5;
    case LEVIT:     return 75;
    case NPOTIONS:  error("Unknown subtype NPOTIONS");
  }
}

string& Potion::guess(Potion::Type subtype) {
  return guesses->at(static_cast<size_t>(subtype));
}

bool Potion::is_known(Potion::Type subtype) {
  return knowledge->at(static_cast<size_t>(subtype));
}

void Potion::set_known(Potion::Type subtype) {
  knowledge->at(static_cast<size_t>(subtype)) = true;
}

Potion::~Potion() {}

Potion::Potion() : Potion(random_potion_type()) {}

Potion::Potion(Potion::Type subtype_) : Item() {
  o_type       = POTION;
  o_which      = subtype_;
  o_count      = 1;
  set_attack_damage({1, 2});
  set_throw_damage({1, 2});

  subtype = subtype_;
}

Potion::Type Potion::get_type() const {
  return subtype;
}

string Potion::get_description() const {
  stringstream os;

  if (Potion::is_known(subtype)) {
    if (o_count == 1) {
      os << "a potion of " << Potion::name(subtype);
    } else {
      os << to_string(o_count) << " potions of " << Potion::name(subtype);
    }

  } else {
    string const& color = *colors->at(static_cast<size_t>(subtype));
    if (o_count == 1) {
      os << "A" << vowelstr(color) << " " << color << " potion";
    } else {
      os << to_string(o_count) << " " << color << " potions";
    }

    string const& nickname = Potion::guess(subtype);
    if (!nickname.empty()) {
      os << " called " << nickname;
    }
  }

  return os.str();
}

void Potion::quaffed_by(Character& victim) {
  switch(static_cast<Potion::Type>(subtype)) {
    case CONFUSION: {
      if (&victim == player && !player->is_hallucinating()) {
        Potion::set_known(subtype);
      }
      victim.set_confused();
    } break;

    case LSD: {
      if (&victim == player) {
        Potion::set_known(subtype);
      }
      victim.set_hallucinating();
   } break;

    case POISON: {
      if (&victim == player) {
        Potion::set_known(subtype);
        player->become_poisoned();
      }
      // Currently, monsters cannot become poisoned. Perks of being a monster.
    } break;

    case STRENGTH: {
      if (&victim == player) {
        Potion::set_known(subtype);
        Game::io->message("you feel stronger, now.  What bulging muscles!");
      }
      victim.modify_strength(1);
    } break;

    case SEEINVIS:  {
      victim.set_true_sight();
    } break;

    case HEALING: {
      if (&victim == player) {
        Potion::set_known(subtype);
        Game::io->message("you begin to feel better");
      }
      victim.restore_health(roll(victim.get_level(), 4), true);
      victim.set_not_blind();
    } break;

    case MFIND: {
      if (&victim == player) {
        Potion::set_known(subtype);
        player->set_sense_monsters();
      }
    } break;

    case TFIND: {
      if (&victim == player) {
        bool show = false;
        if (!Game::level->items.empty()) {
          wclear(Game::io->extra_screen);
          for (Item* item : Game::level->items) {
            if (item->is_magic()) {
              Potion::set_known(subtype);
              show = true;
              mvwaddcch(Game::io->extra_screen, item->get_y(), item->get_x(), MAGIC);
            }
          }

          if (monster_show_if_magic_inventory()) {
            show = true;
          }
        }

        if (show) {
          Potion::set_known(subtype);
          Game::io->show_extra_screen("You sense the presence of magic on this level.--More--");
        } else {
          Game::io->message("you have a strange feeling for a moment, then it passes");
        }
      }
    } break;

    case RAISE: {
      if (&victim == player) {
        Potion::set_known(subtype);
      }
      victim.raise_level(1);
    } break;

    case XHEAL: {
      if (&victim == player) {
        Potion::set_known(subtype);
        Game::io->message("you begin to feel much better");
      }
      victim.restore_health(roll(victim.get_level(), 8), true);
      victim.set_not_blind();
      victim.set_not_hallucinating();
    } break;

    case HASTE: {
      if (&victim == player) {
        Potion::set_known(subtype);
        player->increase_speed();
      }
    } break;

    case RESTORE: {
      victim.restore_strength();
    } break;

    case BLIND: {
      if (&victim == player) {
        Potion::set_known(subtype);
      }
      victim.set_blind();
    } break;

    case LEVIT: {
      if (&victim == player) {
        Potion::set_known(subtype);
      }
      victim.set_levitating();
    } break;

    case NPOTIONS:  error("Unknown subtype NPOTIONS");
  }
}

bool
potion_quaff_something(void)
{
  Potion* obj = dynamic_cast<Potion*>(pack_get_item("quaff", POTION));
  if (obj == nullptr) {
    return false;

  // Make certain that it is somethings that we want to drink
  } else if (obj == nullptr || obj->o_type != POTION) {
    Game::io->message("that's undrinkable");
    return false;
  }

  // Calculate the effect it has on the poor guy.
  bool discardit = obj->o_count == 1;
  pack_remove(obj, false, false);

  obj->quaffed_by(*player);

  Game::io->refresh();

  string& nickname = Potion::guess(obj->get_type());
  if (Potion::is_known(obj->get_type())) {
    nickname.clear();

  } else if (nickname.empty()) {
    Game::io->message("what do you want to call the potion? ");
    nickname = Game::io->read_string();
  }

  /* Throw the item away */
  if (discardit) {
    delete obj;
  }
  return true;
}

void Potion::init_potions() {
  colors = new vector<string const*>;
  knowledge = new vector<bool>(Potion::NPOTIONS, false);
  guesses = new vector<string>(Potion::NPOTIONS, "");

  /* Pick a unique color for each potion */
  for (int i = 0; i < Potion::NPOTIONS; i++)
    for (;;) {
      size_t color = os_rand_range(Color::max());

      if (find(colors->cbegin(), colors->cend(), &Color::get(color)) !=
          colors->cend()) {
        continue;
      }

      colors->push_back(&Color::get(color));
      break;
    }

  // Run some checks
  if (colors->size() != static_cast<size_t>(Potion::NPOTIONS)) {
    error("Potion init: wrong number of colors");
  } else if (knowledge->size() != static_cast<size_t>(Potion::NPOTIONS)) {
    error("Potion init: wrong number of knowledge");
  } else if (guesses->size() != static_cast<size_t>(Potion::NPOTIONS)) {
    error("Potion init: wrong number of guesses");
  }
}

void Potion::free_potions() {
  delete colors;
  colors = nullptr;

  delete knowledge;
  knowledge = nullptr;

  delete guesses;
  guesses = nullptr;
}

<commit_msg>Uncapitalize, Closes #116<commit_after>#include <vector>
#include <string>
#include <sstream>

#include "error_handling.h"
#include "io.h"
#include "pack.h"
#include "level.h"
#include "misc.h"
#include "player.h"
#include "monster.h"
#include "colors.h"
#include "os.h"
#include "rogue.h"
#include "item.h"
#include "game.h"

#include "potions.h"

using namespace std;

std::vector<std::string>*        Potion::guesses;
std::vector<bool>*               Potion::knowledge;
std::vector<std::string const*>* Potion::colors;

static Potion::Type random_potion_type() {
  int value = os_rand_range(100);

  int end = static_cast<int>(Potion::Type::NPOTIONS);
  for (int i = 0; i < end; ++i) {
    Potion::Type type = static_cast<Potion::Type>(i);
    int probability = Potion::probability(type);

    if (value < probability) {
      return type;

    } else {
      value -= probability;
    }
  }

  error("Error! Sum of probabilities is not 100%");
}

Potion* Potion::clone() const {
  return new Potion(*this);
}

bool Potion::is_magic() const {
  return true;
}

string Potion::name(Potion::Type subtype) {
  switch(subtype) {
    case CONFUSION: return "confusion";
    case LSD:       return "hallucination";
    case POISON:    return "poison";
    case STRENGTH:  return "gain strength";
    case SEEINVIS:  return "see invisible";
    case HEALING:   return "healing";
    case MFIND:     return "monster detection";
    case TFIND:     return "magic detection";
    case RAISE:     return "raise level";
    case XHEAL:     return "extra healing";
    case HASTE:     return "haste self";
    case RESTORE:   return "restore strength";
    case BLIND:     return "blindness";
    case LEVIT:     return "levitation";
    case NPOTIONS:  error("Unknown subtype NPOTIONS");
  }
}

int Potion::probability(Potion::Type subtype) {
  switch(subtype) {
    case CONFUSION: return 7;
    case LSD:       return 8;
    case POISON:    return 8;
    case STRENGTH:  return 13;
    case SEEINVIS:  return 3;
    case HEALING:   return 13;
    case MFIND:     return 6;
    case TFIND:     return 6;
    case RAISE:     return 2;
    case XHEAL:     return 5;
    case HASTE:     return 5;
    case RESTORE:   return 13;
    case BLIND:     return 5;
    case LEVIT:     return 6;
    case NPOTIONS:  error("Unknown subtype NPOTIONS");
  }
}

int Potion::worth(Potion::Type subtype) {
  switch(subtype) {
    case CONFUSION: return 5;
    case LSD:       return 5;
    case POISON:    return 5;
    case STRENGTH:  return 150;
    case SEEINVIS:  return 100;
    case HEALING:   return 130;
    case MFIND:     return 130;
    case TFIND:     return 105;
    case RAISE:     return 250;
    case XHEAL:     return 200;
    case HASTE:     return 190;
    case RESTORE:   return 130;
    case BLIND:     return 5;
    case LEVIT:     return 75;
    case NPOTIONS:  error("Unknown subtype NPOTIONS");
  }
}

string& Potion::guess(Potion::Type subtype) {
  return guesses->at(static_cast<size_t>(subtype));
}

bool Potion::is_known(Potion::Type subtype) {
  return knowledge->at(static_cast<size_t>(subtype));
}

void Potion::set_known(Potion::Type subtype) {
  knowledge->at(static_cast<size_t>(subtype)) = true;
}

Potion::~Potion() {}

Potion::Potion() : Potion(random_potion_type()) {}

Potion::Potion(Potion::Type subtype_) : Item() {
  o_type       = POTION;
  o_which      = subtype_;
  o_count      = 1;
  set_attack_damage({1, 2});
  set_throw_damage({1, 2});

  subtype = subtype_;
}

Potion::Type Potion::get_type() const {
  return subtype;
}

string Potion::get_description() const {
  stringstream os;

  if (Potion::is_known(subtype)) {
    if (o_count == 1) {
      os << "a potion of " << Potion::name(subtype);
    } else {
      os << to_string(o_count) << " potions of " << Potion::name(subtype);
    }

  } else {
    string const& color = *colors->at(static_cast<size_t>(subtype));
    if (o_count == 1) {
      os << "a" << vowelstr(color) << " " << color << " potion";
    } else {
      os << to_string(o_count) << " " << color << " potions";
    }

    string const& nickname = Potion::guess(subtype);
    if (!nickname.empty()) {
      os << " called " << nickname;
    }
  }

  return os.str();
}

void Potion::quaffed_by(Character& victim) {
  switch(static_cast<Potion::Type>(subtype)) {
    case CONFUSION: {
      if (&victim == player && !player->is_hallucinating()) {
        Potion::set_known(subtype);
      }
      victim.set_confused();
    } break;

    case LSD: {
      if (&victim == player) {
        Potion::set_known(subtype);
      }
      victim.set_hallucinating();
   } break;

    case POISON: {
      if (&victim == player) {
        Potion::set_known(subtype);
        player->become_poisoned();
      }
      // Currently, monsters cannot become poisoned. Perks of being a monster.
    } break;

    case STRENGTH: {
      if (&victim == player) {
        Potion::set_known(subtype);
        Game::io->message("you feel stronger, now.  What bulging muscles!");
      }
      victim.modify_strength(1);
    } break;

    case SEEINVIS:  {
      victim.set_true_sight();
    } break;

    case HEALING: {
      if (&victim == player) {
        Potion::set_known(subtype);
        Game::io->message("you begin to feel better");
      }
      victim.restore_health(roll(victim.get_level(), 4), true);
      victim.set_not_blind();
    } break;

    case MFIND: {
      if (&victim == player) {
        Potion::set_known(subtype);
        player->set_sense_monsters();
      }
    } break;

    case TFIND: {
      if (&victim == player) {
        bool show = false;
        if (!Game::level->items.empty()) {
          wclear(Game::io->extra_screen);
          for (Item* item : Game::level->items) {
            if (item->is_magic()) {
              Potion::set_known(subtype);
              show = true;
              mvwaddcch(Game::io->extra_screen, item->get_y(), item->get_x(), MAGIC);
            }
          }

          if (monster_show_if_magic_inventory()) {
            show = true;
          }
        }

        if (show) {
          Potion::set_known(subtype);
          Game::io->show_extra_screen("You sense the presence of magic on this level.--More--");
        } else {
          Game::io->message("you have a strange feeling for a moment, then it passes");
        }
      }
    } break;

    case RAISE: {
      if (&victim == player) {
        Potion::set_known(subtype);
      }
      victim.raise_level(1);
    } break;

    case XHEAL: {
      if (&victim == player) {
        Potion::set_known(subtype);
        Game::io->message("you begin to feel much better");
      }
      victim.restore_health(roll(victim.get_level(), 8), true);
      victim.set_not_blind();
      victim.set_not_hallucinating();
    } break;

    case HASTE: {
      if (&victim == player) {
        Potion::set_known(subtype);
        player->increase_speed();
      }
    } break;

    case RESTORE: {
      victim.restore_strength();
    } break;

    case BLIND: {
      if (&victim == player) {
        Potion::set_known(subtype);
      }
      victim.set_blind();
    } break;

    case LEVIT: {
      if (&victim == player) {
        Potion::set_known(subtype);
      }
      victim.set_levitating();
    } break;

    case NPOTIONS:  error("Unknown subtype NPOTIONS");
  }
}

bool
potion_quaff_something(void)
{
  Potion* obj = dynamic_cast<Potion*>(pack_get_item("quaff", POTION));
  if (obj == nullptr) {
    return false;

  // Make certain that it is somethings that we want to drink
  } else if (obj == nullptr || obj->o_type != POTION) {
    Game::io->message("that's undrinkable");
    return false;
  }

  // Calculate the effect it has on the poor guy.
  bool discardit = obj->o_count == 1;
  pack_remove(obj, false, false);

  obj->quaffed_by(*player);

  Game::io->refresh();

  string& nickname = Potion::guess(obj->get_type());
  if (Potion::is_known(obj->get_type())) {
    nickname.clear();

  } else if (nickname.empty()) {
    Game::io->message("what do you want to call the potion? ");
    nickname = Game::io->read_string();
  }

  /* Throw the item away */
  if (discardit) {
    delete obj;
  }
  return true;
}

void Potion::init_potions() {
  colors = new vector<string const*>;
  knowledge = new vector<bool>(Potion::NPOTIONS, false);
  guesses = new vector<string>(Potion::NPOTIONS, "");

  /* Pick a unique color for each potion */
  for (int i = 0; i < Potion::NPOTIONS; i++)
    for (;;) {
      size_t color = os_rand_range(Color::max());

      if (find(colors->cbegin(), colors->cend(), &Color::get(color)) !=
          colors->cend()) {
        continue;
      }

      colors->push_back(&Color::get(color));
      break;
    }

  // Run some checks
  if (colors->size() != static_cast<size_t>(Potion::NPOTIONS)) {
    error("Potion init: wrong number of colors");
  } else if (knowledge->size() != static_cast<size_t>(Potion::NPOTIONS)) {
    error("Potion init: wrong number of knowledge");
  } else if (guesses->size() != static_cast<size_t>(Potion::NPOTIONS)) {
    error("Potion init: wrong number of guesses");
  }
}

void Potion::free_potions() {
  delete colors;
  colors = nullptr;

  delete knowledge;
  knowledge = nullptr;

  delete guesses;
  guesses = nullptr;
}

<|endoftext|>


<commit_before>// Copyright (c) 2017 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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.
#include <cstdint>
#include <Chaos/Codecs/Crc32c.h>
#include <Chaos/Unittest/TestHarness.h>

CHAOS_TEST(Crc32c, Chaos::FakeTester) {
  namespace cc = Chaos::Crc32c;

  char buf[32]{};
  CHAOS_CHECK_EQ(0x8a9136aau, cc::value(buf, sizeof(buf)));

  memset(buf, 0xff, sizeof(buf));
  CHAOS_CHECK_EQ(0x62a8ab43u, cc::value(buf, sizeof(buf)));

  for (auto i = 0; i < 32; ++i)
    buf[i] = i;
  CHAOS_CHECK_EQ(0x46dd794eu, cc::value(buf, sizeof(buf)));

  for (auto i = 0; i < 32; ++i)
    buf[i] = 31 - i;
  CHAOS_CHECK_EQ(0x113fdb5cu, cc::value(buf, sizeof(buf)));

  CHAOS_CHECK_NE(cc::value("a", 1), cc::value("foo", 3));
  CHAOS_CHECK_EQ(cc::value("ChaosCrc32c", 11),
      cc::extend(cc::value("Chaos", 5), "Crc32c", 6));

  std::uint32_t init_crc = cc::value("foo", 3);
  CHAOS_CHECK_NE(init_crc, cc::mask(init_crc));
  CHAOS_CHECK_NE(init_crc, cc::mask(cc::mask(init_crc)));
  CHAOS_CHECK_EQ(init_crc, cc::unmask(cc::mask(init_crc)));
  CHAOS_CHECK_EQ(init_crc,
      cc::unmask(cc::unmask(cc::mask(cc::mask(init_crc)))));
}
<commit_msg>:bug: fix(crc32): fixed bug for unittest of crc32 module<commit_after>// Copyright (c) 2017 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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.
#include <cstdint>
#include <cstring>
#include <Chaos/Codecs/Crc32c.h>
#include <Chaos/Unittest/TestHarness.h>

CHAOS_TEST(Crc32c, Chaos::FakeTester) {
  namespace cc = Chaos::Crc32c;

  char buf[32]{};
  CHAOS_CHECK_EQ(0x8a9136aau, cc::value(buf, sizeof(buf)));

  std::memset(buf, 0xff, sizeof(buf));
  CHAOS_CHECK_EQ(0x62a8ab43u, cc::value(buf, sizeof(buf)));

  for (auto i = 0; i < 32; ++i)
    buf[i] = i;
  CHAOS_CHECK_EQ(0x46dd794eu, cc::value(buf, sizeof(buf)));

  for (auto i = 0; i < 32; ++i)
    buf[i] = 31 - i;
  CHAOS_CHECK_EQ(0x113fdb5cu, cc::value(buf, sizeof(buf)));

  CHAOS_CHECK_NE(cc::value("a", 1), cc::value("foo", 3));
  CHAOS_CHECK_EQ(cc::value("ChaosCrc32c", 11),
      cc::extend(cc::value("Chaos", 5), "Crc32c", 6));

  std::uint32_t init_crc = cc::value("foo", 3);
  CHAOS_CHECK_NE(init_crc, cc::mask(init_crc));
  CHAOS_CHECK_NE(init_crc, cc::mask(cc::mask(init_crc)));
  CHAOS_CHECK_EQ(init_crc, cc::unmask(cc::mask(init_crc)));
  CHAOS_CHECK_EQ(init_crc,
      cc::unmask(cc::unmask(cc::mask(cc::mask(init_crc)))));
}
<|endoftext|>