<commit_before>/**
  * @file hmi.cpp
  * @brief The implementation of class HMI.
  * @author laicheng.zhang@itead.cc
  * @date 2015.04
  *
  * @par Copyright:
  * Copyright (c) 2015 ITEAD Intelligent Systems Co., Ltd. \n\n
  * 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. \n\n
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */

#include "hmi.h"
HMI::HMI(HMISerial &uart,uint32_t baud)
{
	my_uart = &uart;
        my_uart->begin(baud);
        setRxEmpty();
}

bool HMI::textEdit(char *text_id,char *value)
{
	/*t0.txt="abc"*/
	char cmd[50] = {0};
	strcat(cmd,text_id);
	strcat(cmd,".txt=\"");
	strcat(cmd,value);
	strcat(cmd,"\"");
	my_uart->print(cmd);
        commandEnd();

	if (returnIsRight() == 0)
		return true;
        else
		return false;
}

bool HMI::pictureEdit(char *picture_id,uint32_t value)
{
	/*p0.pic=6*/
	char cmd[50] = {0};
	char valuetemp[25] = {0};
	itoa(value,valuetemp,10);
	strcat(cmd,picture_id);
	strcat(cmd,".pic=");
	strcat(cmd,valuetemp);

	my_uart->print(cmd);
	commandEnd();

	if (returnIsRight() == 0)
	return true;
		else
	return false;
}

bool HMI::progressBarEdit(char *bar_id,uint32_t value)
{
	char  cmd[50] = {0};
	char valuetemp[25] = {0};
	itoa(value,valuetemp,10);
	strcat(cmd,bar_id);
	strcat(cmd,".val=");
	strcat(cmd,valuetemp);

	my_uart->print(cmd);
	commandEnd();

	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

bool HMI::cutPicture(char *picture_id,uint32_t value)
{
	char cmd[50] = {0};
	char valuetemp[25] = {0};
	itoa(value,valuetemp,10);
	strcat(cmd,picture_id);
	strcat(cmd,".pic=");
	strcat(cmd,valuetemp);

	my_uart->print(cmd);
	commandEnd();

	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

bool HMI::pageChange(uint32_t page_id)
{
	char  cmd[50] = {0};
	char page_idtemp[25] = {0};
	itoa(page_id,page_idtemp,10);
	strcat(cmd,"page");
	strcat(cmd," ");
	strcat(cmd,page_idtemp);
	my_uart->print(cmd);

	commandEnd();
	delay(200);
	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

void HMI::readLcdData(unsigned char *data_buffer)
{
	delay(10);
	cleanBuffer();
	uint32_t i = 0;
	while(my_uart->available() <= 0);
	while(my_uart->available() > 0)
	{
		delay(3);
		buffer[i] = (unsigned char)my_uart->read();
		i++;
	}
	if (buffer[0] == 0x70)
	{
		uint32_t j = 0;
		uint32_t k = 1;
		for(j=0;j<strlen((char*)buffer)-4;)
		{
			data_buffer[j]=buffer[k];
			j++;
			k++;
		}
	}
}

bool HMI::returnIsRight(void)
{
	delay(10);
	uint32_t tempid = 0;
	unsigned char temp[20] = {0};
	unsigned char temp1[4] = {0x01,0xFF,0xFF,0xFF};

	tempid = my_uart->available();
	uint32_t i = 0;
	while(my_uart->available())
	{
		temp[i] = (unsigned char)my_uart->read();
		i++;
	}
	if((tempid==4)&&(strncmp((char*)temp1,(char*)temp,4)==0))
	{
		return 0;
	}
	else
	{
		return -1;
	}
}

bool HMI::touchCalibration(void)
{
	/*Serial.println("touch Calibration");*/
	my_uart->print("touch_j");
	commandEnd();
	delay(5000);
	if (returnIsRight() == 0)
		return true;
	else
		return false;

}

bool HMI::disableTouchFocus(void)
{
	    /*Serial.println("disableTouchFocus");*/
	my_uart->print("cle_c");
	commandEnd();
	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

bool HMI::pauseSerialCommand(void)
{
	/*Serial.println("pauseSerialCommand");*/
	my_uart->print("com_stop");
	commandEnd();
	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

bool HMI::recoverySerialCommand(void)
{
	/*Serial.println("recoverySerialCommand");*/
	my_uart->print("com_star");
	commandEnd();
	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

bool HMI::emptySerialCommand(void)
{
	/*Serial.println("emptySerialCommand");*/
	my_uart->print("code_c");
	commandEnd();
	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

uint32_t HMI::returnPageId(void)
{
	my_uart->print("sendme");
	commandEnd();

	delay(50);
	unsigned char temp1[] = {0x66,0xFF,0xFF,0xFF};
	unsigned char temp[10] = {0};
	uint32_t j = 0;
	while(my_uart->available() > 0)
	{
		temp[j] = (unsigned char)my_uart->read();
		delay(3);
		j++;
	}

	if(!strcmp((char*)temp1[0],(char*)temp[0]))
	{
		return (uint32_t)temp[1];
	}
	else
		return -1;
}

void HMI::setRxEmpty(void)
{
	while(my_uart->available() > 0)
	{
		my_uart->read();
	}
}

void HMI::cleanBuffer(void)
{
	memset(buffer,0,strlen((char*)buffer));
}

void HMI::commandEnd(void)
{
	my_uart->write(0xFF);
        my_uart->write(0xFF);
        my_uart->write(0xFF);
}

<commit_msg>Update hmi.cpp<commit_after>/**
  * @file hmi.cpp
  * @brief The implementation of class HMI.
  * @author laicheng.zhang@itead.cc
  * @date 2015.04
  */

#include "hmi.h"
HMI::HMI(HMISerial &uart,uint32_t baud)
{
	my_uart = &uart;
        my_uart->begin(baud);
        setRxEmpty();
}

bool HMI::textEdit(char *text_id,char *value)
{
	/*t0.txt="abc"*/
	char cmd[50] = {0};
	strcat(cmd,text_id);
	strcat(cmd,".txt=\"");
	strcat(cmd,value);
	strcat(cmd,"\"");
	my_uart->print(cmd);
        commandEnd();

	if (returnIsRight() == 0)
		return true;
        else
		return false;
}

bool HMI::pictureEdit(char *picture_id,uint32_t value)
{
	/*p0.pic=6*/
	char cmd[50] = {0};
	char valuetemp[25] = {0};
	itoa(value,valuetemp,10);
	strcat(cmd,picture_id);
	strcat(cmd,".pic=");
	strcat(cmd,valuetemp);

	my_uart->print(cmd);
	commandEnd();

	if (returnIsRight() == 0)
	return true;
		else
	return false;
}

bool HMI::progressBarEdit(char *bar_id,uint32_t value)
{
	char  cmd[50] = {0};
	char valuetemp[25] = {0};
	itoa(value,valuetemp,10);
	strcat(cmd,bar_id);
	strcat(cmd,".val=");
	strcat(cmd,valuetemp);

	my_uart->print(cmd);
	commandEnd();

	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

bool HMI::cutPicture(char *picture_id,uint32_t value)
{
	char cmd[50] = {0};
	char valuetemp[25] = {0};
	itoa(value,valuetemp,10);
	strcat(cmd,picture_id);
	strcat(cmd,".pic=");
	strcat(cmd,valuetemp);

	my_uart->print(cmd);
	commandEnd();

	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

bool HMI::pageChange(uint32_t page_id)
{
	char  cmd[50] = {0};
	char page_idtemp[25] = {0};
	itoa(page_id,page_idtemp,10);
	strcat(cmd,"page");
	strcat(cmd," ");
	strcat(cmd,page_idtemp);
	my_uart->print(cmd);

	commandEnd();
	delay(200);
	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

void HMI::readLcdData(unsigned char *data_buffer)
{
	delay(10);
	cleanBuffer();
	uint32_t i = 0;
	while(my_uart->available() <= 0);
	while(my_uart->available() > 0)
	{
		delay(3);
		buffer[i] = (unsigned char)my_uart->read();
		i++;
	}
	if (buffer[0] == 0x70)
	{
		uint32_t j = 0;
		uint32_t k = 1;
		for(j=0;j<strlen((char*)buffer)-4;)
		{
			data_buffer[j]=buffer[k];
			j++;
			k++;
		}
	}
}

bool HMI::returnIsRight(void)
{
	delay(10);
	uint32_t tempid = 0;
	unsigned char temp[20] = {0};
	unsigned char temp1[4] = {0x01,0xFF,0xFF,0xFF};

	tempid = my_uart->available();
	uint32_t i = 0;
	while(my_uart->available())
	{
		temp[i] = (unsigned char)my_uart->read();
		i++;
	}
	if((tempid==4)&&(strncmp((char*)temp1,(char*)temp,4)==0))
	{
		return 0;
	}
	else
	{
		return -1;
	}
}

bool HMI::touchCalibration(void)
{
	/*Serial.println("touch Calibration");*/
	my_uart->print("touch_j");
	commandEnd();
	delay(5000);
	if (returnIsRight() == 0)
		return true;
	else
		return false;

}

bool HMI::disableTouchFocus(void)
{
	    /*Serial.println("disableTouchFocus");*/
	my_uart->print("cle_c");
	commandEnd();
	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

bool HMI::pauseSerialCommand(void)
{
	/*Serial.println("pauseSerialCommand");*/
	my_uart->print("com_stop");
	commandEnd();
	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

bool HMI::recoverySerialCommand(void)
{
	/*Serial.println("recoverySerialCommand");*/
	my_uart->print("com_star");
	commandEnd();
	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

bool HMI::emptySerialCommand(void)
{
	/*Serial.println("emptySerialCommand");*/
	my_uart->print("code_c");
	commandEnd();
	if (returnIsRight() == 0)
		return true;
	else
		return false;
}

uint32_t HMI::returnPageId(void)
{
	my_uart->print("sendme");
	commandEnd();

	delay(50);
	unsigned char temp1[] = {0x66,0xFF,0xFF,0xFF};
	unsigned char temp[10] = {0};
	uint32_t j = 0;
	while(my_uart->available() > 0)
	{
		temp[j] = (unsigned char)my_uart->read();
		delay(3);
		j++;
	}

	if(!strcmp((char*)temp1[0],(char*)temp[0]))
	{
		return (uint32_t)temp[1];
	}
	else
		return -1;
}

void HMI::setRxEmpty(void)
{
	while(my_uart->available() > 0)
	{
		my_uart->read();
	}
}

void HMI::cleanBuffer(void)
{
	memset(buffer,0,strlen((char*)buffer));
}

void HMI::commandEnd(void)
{
	my_uart->write(0xFF);
        my_uart->write(0xFF);
        my_uart->write(0xFF);
}

<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                     The Descent map loader
//
// NAME         : Hog
// PURPOSE      : Providing a decoder and wrapper for the Descent .HOG format.
// COPYRIGHT    : (c) 2011 Sean Donnellan. All Rights Reserved.
// AUTHORS      : Sean Donnellan (darkdonno@gmail.com)
// DESCRIPTION  : A decoder for the HOG file format that is used by Parallax
//                Software in the computer game, Descent.
//
//                The file format is as follows:
//
//                - Magic number which is 3 bytes and corresponding to the
//                  string "DHF"

//                - A series of files which are preceded by a short header,
//                  which describes the name of the file and the numer of bytes.
//
//                 | "DHF" - 3 bytes
//                 |---------------- Start of the first file
//                 | filename - 13 bytes
//                 | size - 4 bytes
//                 | data - the size of this part is by the size before it.
//                 |---------------- The next header/file comes straight after.
//                 | filename - 13 bytes
//                 | size - 4 bytes
//                 | data - the size of this part is by the size before it.
//
//===----------------------------------------------------------------------===//

/////
// Developer notes
// Different file formats: http://www.descent2.com/ddn/kb/files/
//
/////

#include "hogreader.hpp"
#include "hogiterator.hpp"
#include "rdl.hpp"

#include <memory>
#include <iterator>
#include <utility>
#include <vector>

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef _MSC_VER
static_assert(sizeof(uint8_t) == 1,
              "The size of uint8_t is incorrect it must be 1-byte");
static_assert(sizeof(uint32_t) == 4,
              "The size of uint32_t is incorrect it must be 4-bytes");
static_assert(sizeof(uint8_t) == sizeof(char),
              "The size of a char must be 1-byte");
#endif

// The 3-byte MAGIC number at the start of the file format used to identifiy the
// file as being a Descent HOG file.
static uint8_t magic[3] = {'D', 'H', 'F'};

HogReader::iterator HogReader::begin()
{
  // Sync back up to the start just after the magic number.
  if (IsValid())
  {
    fseek(myFile, sizeof(magic), SEEK_SET);
    if (fread(&myChildFile.name, 13, 1, myFile) != 1) HogReaderIterator();
    if (fread(&myChildFile.size, 4, 1, myFile) != 1) HogReaderIterator();
  }

  return HogReaderIterator(*this);
}

HogReader::iterator HogReader::end() { return HogReaderIterator(); }

HogReader::HogReader(const char* filename) : myFile(nullptr)
{
  myFile = fopen(filename, "rb");
  myChildFile.name[0] = '\0';
  myChildFile.size = 0;
  if (!myFile) return;

  const size_t count = 1;
  if (fread(myHeader, sizeof(myHeader), count, myFile) != count)
  {
    myHeader[0] = '\0'; // Failed to load.
    return;
  }

  // Read in the header for the first file.
  if (IsValid())
  {
    if (fread(&myChildFile.name, 13, 1, myFile) != 1) return;
    if (fread(&myChildFile.size, 4, 1, myFile) != 1) return;
  }
}

HogReader::~HogReader()
{
  if (myFile) fclose(myFile);
}

bool HogReader::IsValid() const
{
  if (!myFile) return false;
  return memcmp(myHeader, magic, 3) == 0;
}

bool HogReader::NextFile()
{
  // Skip the current file.
  if (feof(myFile)) return false;

  if (!hasReadFile)
  {
    // The data for the current file has not been read so skip over the data
    // section
    // for the file.

    if (fseek(myFile, myChildFile.size, SEEK_CUR) != 0) return false;
  }

  // Read in the header for the next file.
  if (fread(&myChildFile.name, 13, 1, myFile) != 1) return false;
  if (fread(&myChildFile.size, 4, 1, myFile) != 1) return false;

  hasReadFile = false; // We haven't read the next file yet.
  return true;
}

const char* HogReader::CurrentFileName() const { return myChildFile.name; }

unsigned int HogReader::CurrentFileSize() const { return myChildFile.size; }

std::vector<uint8_t> HogReader::CurrentFile()
{
  std::vector<uint8_t> fileData;

  // TODO: Allow this to seek-back and read it again.
  //
  // For now ensure the current file hasn't been read yet.
  assert(!hasReadFile);

  // Skip the current file.
  if (feof(myFile)) return fileData;

  const unsigned int size = CurrentFileSize(); // Size in bytes
  fileData.resize(size);

  if (fread(fileData.data(), size, 1, myFile) != 1)
  {
    fileData.clear();
  }

  return fileData;
}

#include <string>
#include <algorithm>

int main(int argc, char* argv[])
{
  if (argc != 2)
  {
    printf("usage: %s filename\n", argv[0]);
    return 1;
  }

  HogReader reader(argv[1]);
  if (!reader.IsValid())
  {
    fprintf(stderr, "error to open the hog file");
    return 1;
  }

  // File list.
  const bool listingAllFiles = false;
  if (listingAllFiles)
  {
    printf("Filename\n");
    printf("========\n");
    std::for_each(reader.begin(), reader.end(),
                  [](HogReader::iterator::value_type n)
    { printf("%s %p\n", n.first, n.second); });
  }
  else
  {
    // Iterate over the file list and list all the files which do not
    // end in the 'rdl' file extension.
    const std::string extentionRdl(".rdl");
    std::for_each(reader.begin(), reader.end(),
                  [&extentionRdl](HogReader::iterator::value_type n)
    {
      const std::string filename(n.first);
      if (!std::equal(extentionRdl.rbegin(), extentionRdl.rend(),
                      filename.rbegin()))
        return;

      printf("%s %d\n", n.first, n.second->CurrentFileSize());
      const auto data = n.second->CurrentFile();
      RdlReader rdlReader(data);
      printf("Is valid RDL: %s\n", rdlReader.IsValid() ? "Yes" : "No");

      if (!rdlReader.IsValid()) return;

      const auto vertices = rdlReader.Vertices();
      printf("Vertex count: %d\n", vertices.size());
      std::for_each(vertices.begin(), vertices.end(),
                    [](Vertex v)
                    { printf("%16f %16f %16f\n", v.x, v.y, v.z); });

      exit(0);
    });
  }
  return 0;
}
<commit_msg>Changed over the main function to call DoStuff() which tries to parse the cubes in the RDL file.<commit_after>//===----------------------------------------------------------------------===//
//
//                     The Descent map loader
//
// NAME         : Hog
// PURPOSE      : Providing a decoder and wrapper for the Descent .HOG format.
// COPYRIGHT    : (c) 2011 Sean Donnellan. All Rights Reserved.
// AUTHORS      : Sean Donnellan (darkdonno@gmail.com)
// DESCRIPTION  : A decoder for the HOG file format that is used by Parallax
//                Software in the computer game, Descent.
//
//                The file format is as follows:
//
//                - Magic number which is 3 bytes and corresponding to the
//                  string "DHF"

//                - A series of files which are preceded by a short header,
//                  which describes the name of the file and the numer of bytes.
//
//                 | "DHF" - 3 bytes
//                 |---------------- Start of the first file
//                 | filename - 13 bytes
//                 | size - 4 bytes
//                 | data - the size of this part is by the size before it.
//                 |---------------- The next header/file comes straight after.
//                 | filename - 13 bytes
//                 | size - 4 bytes
//                 | data - the size of this part is by the size before it.
//
//===----------------------------------------------------------------------===//

/////
// Developer notes
// Different file formats: http://www.descent2.com/ddn/kb/files/
//
/////

#include "hogreader.hpp"
#include "hogiterator.hpp"
#include "rdl.hpp"

#include <memory>
#include <iterator>
#include <utility>
#include <vector>

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef _MSC_VER
static_assert(sizeof(uint8_t) == 1,
              "The size of uint8_t is incorrect it must be 1-byte");
static_assert(sizeof(uint32_t) == 4,
              "The size of uint32_t is incorrect it must be 4-bytes");
static_assert(sizeof(uint8_t) == sizeof(char),
              "The size of a char must be 1-byte");
#endif

// The 3-byte MAGIC number at the start of the file format used to identifiy the
// file as being a Descent HOG file.
static uint8_t magic[3] = {'D', 'H', 'F'};

HogReader::iterator HogReader::begin()
{
  // Sync back up to the start just after the magic number.
  if (IsValid())
  {
    fseek(myFile, sizeof(magic), SEEK_SET);
    if (fread(&myChildFile.name, 13, 1, myFile) != 1) HogReaderIterator();
    if (fread(&myChildFile.size, 4, 1, myFile) != 1) HogReaderIterator();
  }

  return HogReaderIterator(*this);
}

HogReader::iterator HogReader::end() { return HogReaderIterator(); }

HogReader::HogReader(const char* filename) : myFile(nullptr)
{
  myFile = fopen(filename, "rb");
  myChildFile.name[0] = '\0';
  myChildFile.size = 0;
  if (!myFile) return;

  const size_t count = 1;
  if (fread(myHeader, sizeof(myHeader), count, myFile) != count)
  {
    myHeader[0] = '\0'; // Failed to load.
    return;
  }

  // Read in the header for the first file.
  if (IsValid())
  {
    if (fread(&myChildFile.name, 13, 1, myFile) != 1) return;
    if (fread(&myChildFile.size, 4, 1, myFile) != 1) return;
  }
}

HogReader::~HogReader()
{
  if (myFile) fclose(myFile);
}

bool HogReader::IsValid() const
{
  if (!myFile) return false;
  return memcmp(myHeader, magic, 3) == 0;
}

bool HogReader::NextFile()
{
  // Skip the current file.
  if (feof(myFile)) return false;

  if (!hasReadFile)
  {
    // The data for the current file has not been read so skip over the data
    // section
    // for the file.

    if (fseek(myFile, myChildFile.size, SEEK_CUR) != 0) return false;
  }

  // Read in the header for the next file.
  if (fread(&myChildFile.name, 13, 1, myFile) != 1) return false;
  if (fread(&myChildFile.size, 4, 1, myFile) != 1) return false;

  hasReadFile = false; // We haven't read the next file yet.
  return true;
}

const char* HogReader::CurrentFileName() const { return myChildFile.name; }

unsigned int HogReader::CurrentFileSize() const { return myChildFile.size; }

std::vector<uint8_t> HogReader::CurrentFile()
{
  std::vector<uint8_t> fileData;

  // TODO: Allow this to seek-back and read it again.
  //
  // For now ensure the current file hasn't been read yet.
  assert(!hasReadFile);

  // Skip the current file.
  if (feof(myFile)) return fileData;

  const unsigned int size = CurrentFileSize(); // Size in bytes
  fileData.resize(size);

  if (fread(fileData.data(), size, 1, myFile) != 1)
  {
    fileData.clear();
  }

  return fileData;
}

#include <string>
#include <algorithm>

int main(int argc, char* argv[])
{
  if (argc != 2)
  {
    printf("usage: %s filename\n", argv[0]);
    return 1;
  }

  HogReader reader(argv[1]);
  if (!reader.IsValid())
  {
    fprintf(stderr, "error to open the hog file");
    return 1;
  }

  // File list.
  const bool listingAllFiles = false;
  if (listingAllFiles)
  {
    printf("Filename\n");
    printf("========\n");
    std::for_each(reader.begin(), reader.end(),
                  [](HogReader::iterator::value_type n)
    { printf("%s %p\n", n.first, n.second); });
  }
  else
  {
    // Iterate over the file list and list all the files which do not
    // end in the 'rdl' file extension.
    const std::string extentionRdl(".rdl");
    std::for_each(reader.begin(), reader.end(),
                  [&extentionRdl](HogReader::iterator::value_type n)
    {
      const std::string filename(n.first);
      if (!std::equal(extentionRdl.rbegin(), extentionRdl.rend(),
                      filename.rbegin()))
        return;

      printf("%s %d\n", n.first, n.second->CurrentFileSize());
      const auto data = n.second->CurrentFile();
      RdlReader rdlReader(data);
      printf("Is valid RDL: %s\n", rdlReader.IsValid() ? "Yes" : "No");

      if (!rdlReader.IsValid()) return;

      /*
      // Print out the vertices.
      const auto vertices = rdlReader.Vertices();
      printf("Vertex count: %d\n", vertices.size());
      std::for_each(vertices.begin(), vertices.end(),
                    [](Vertex v)
                    { printf("%16f %16f %16f\n", v.x, v.y, v.z); });
      */
      rdlReader.DoStuff();

      exit(0);
    });
  }
  return 0;
}
<|endoftext|>


<commit_before>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/
#include "ProgressDialogManager.h"

#include "DataSource.h"
#include "ModuleManager.h"
#include "Operator.h"

#include <QCoreApplication>
#include <QDialog>
#include <QDialogButtonBox>
#include <QMainWindow>
#include <QMap>
#include <QProgressBar>
#include <QStatusBar>
#include <QVBoxLayout>

#include <cassert>
#include <iostream>

namespace tomviz {

ProgressDialogManager::ProgressDialogManager(QMainWindow* mw)
  : Superclass(mw), mainWindow(mw)
{
  ModuleManager& mm = ModuleManager::instance();
  QObject::connect(&mm, SIGNAL(dataSourceAdded(DataSource*)), this,
                   SLOT(dataSourceAdded(DataSource*)));
}

ProgressDialogManager::~ProgressDialogManager()
{
}

void ProgressDialogManager::operationStarted()
{
  QDialog* progressDialog = new QDialog(this->mainWindow);
  progressDialog->setAttribute(Qt::WA_DeleteOnClose);

  Operator* op = qobject_cast<Operator*>(this->sender());
  QObject::connect(op, &Operator::transformingDone, progressDialog,
                   &QDialog::accept);

  // We have to check after we have connected to the signal as otherwise we
  // might miss the state transition as its occurring on another thread.
  if (op->isFinished()) {
    progressDialog->accept();
    progressDialog->deleteLater();
    return;
  }

  QLayout* layout = new QVBoxLayout();
  QWidget* progressWidget = op->getCustomProgressWidget(progressDialog);
  if (progressWidget == nullptr) {
    QProgressBar* progressBar = new QProgressBar(progressDialog);
    progressBar->setMinimum(0);
    progressBar->setMaximum(op->totalProgressSteps());
    progressWidget = progressBar;
    QObject::connect(op, &Operator::progressStepChanged, progressBar,
                     &QProgressBar::setValue);
    QObject::connect(op, &Operator::totalProgressStepsChanged, progressBar,
                     &QProgressBar::setMaximum);
    QObject::connect(op, &Operator::progressStepChanged, this,
                     &ProgressDialogManager::operationProgress);
    QObject::connect(
      op, &Operator::progressMessageChanged,
      [progressDialog, op](const QString& message) {
        if (!message.isNull()) {
          QString title = QString("%1 Progress").arg(op->label());
          if (!message.isEmpty()) {
            title = QString("%1 Progress - %2").arg(op->label()).arg(message);
          }
          progressDialog->setWindowTitle(title);
        }
      });
    QObject::connect(progressDialog, &QDialog::rejected, [op]() {
      QObject::disconnect(op, &Operator::progressMessageChanged, nullptr,
                          nullptr);
    });

    connect(op, &Operator::progressMessageChanged, this,
            &ProgressDialogManager::showStatusBarMessage);

    layout->addWidget(progressBar);
  }
  layout->addWidget(progressWidget);
  if (op->supportsCancelingMidTransform()) {
    // Unless the widget has custom progress handling, you can't cancel it.
    QDialogButtonBox* dialogButtons = new QDialogButtonBox(
      QDialogButtonBox::Cancel, Qt::Horizontal, progressDialog);
    layout->addWidget(dialogButtons);
    QObject::connect(dialogButtons, &QDialogButtonBox::rejected, op,
                     &Operator::cancelTransform);
    QObject::connect(dialogButtons, &QDialogButtonBox::rejected, progressDialog,
                     &QDialog::reject);
  }
  progressDialog->setWindowTitle(QString("%1 Progress").arg(op->label()));
  progressDialog->setLayout(layout);
  progressDialog->adjustSize();
  // Increase size of dialog so we can see title, not sure there is a better
  // way.
  auto height = progressDialog->height();
  progressDialog->resize(500, height);
  progressDialog->show();
  QCoreApplication::processEvents();
}

void ProgressDialogManager::operatorAdded(Operator* op)
{
  connect(op, &Operator::transformingStarted, this,
          &ProgressDialogManager::operationStarted,
          Qt::BlockingQueuedConnection);

  connect(op, &Operator::newChildDataSource, this,
          &ProgressDialogManager::dataSourceAdded);
}

void ProgressDialogManager::dataSourceAdded(DataSource* ds)
{
  QObject::connect(ds, SIGNAL(operatorAdded(Operator*)), this,
                   SLOT(operatorAdded(Operator*)));
}

void ProgressDialogManager::operationProgress(int)
{
  // Probably not strictly neccessary in the long run where we have a background
  // thread, until then we need this call.
  QCoreApplication::processEvents();
}

void ProgressDialogManager::showStatusBarMessage(const QString& message)
{
  this->mainWindow->statusBar()->showMessage(message, 3000);
}
}
<commit_msg>Make closing the progress dialog the same as pressing Cancel<commit_after>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/
#include "ProgressDialogManager.h"

#include "DataSource.h"
#include "ModuleManager.h"
#include "Operator.h"

#include <QCoreApplication>
#include <QDialog>
#include <QDialogButtonBox>
#include <QMainWindow>
#include <QMap>
#include <QProgressBar>
#include <QStatusBar>
#include <QVBoxLayout>

#include <cassert>
#include <iostream>

namespace tomviz {

ProgressDialogManager::ProgressDialogManager(QMainWindow* mw)
  : Superclass(mw), mainWindow(mw)
{
  ModuleManager& mm = ModuleManager::instance();
  QObject::connect(&mm, SIGNAL(dataSourceAdded(DataSource*)), this,
                   SLOT(dataSourceAdded(DataSource*)));
}

ProgressDialogManager::~ProgressDialogManager()
{
}

void ProgressDialogManager::operationStarted()
{
  QDialog* progressDialog = new QDialog(this->mainWindow);
  progressDialog->setAttribute(Qt::WA_DeleteOnClose);

  Operator* op = qobject_cast<Operator*>(this->sender());
  QObject::connect(op, &Operator::transformingDone, progressDialog,
                   &QDialog::accept);

  // We have to check after we have connected to the signal as otherwise we
  // might miss the state transition as its occurring on another thread.
  if (op->isFinished()) {
    progressDialog->accept();
    progressDialog->deleteLater();
    return;
  }

  QLayout* layout = new QVBoxLayout();
  QWidget* progressWidget = op->getCustomProgressWidget(progressDialog);
  if (progressWidget == nullptr) {
    QProgressBar* progressBar = new QProgressBar(progressDialog);
    progressBar->setMinimum(0);
    progressBar->setMaximum(op->totalProgressSteps());
    progressWidget = progressBar;
    QObject::connect(op, &Operator::progressStepChanged, progressBar,
                     &QProgressBar::setValue);
    QObject::connect(op, &Operator::totalProgressStepsChanged, progressBar,
                     &QProgressBar::setMaximum);
    QObject::connect(op, &Operator::progressStepChanged, this,
                     &ProgressDialogManager::operationProgress);
    QObject::connect(
      op, &Operator::progressMessageChanged,
      [progressDialog, op](const QString& message) {
        if (!message.isNull()) {
          QString title = QString("%1 Progress").arg(op->label());
          if (!message.isEmpty()) {
            title = QString("%1 Progress - %2").arg(op->label()).arg(message);
          }
          progressDialog->setWindowTitle(title);
        }
      });
    QObject::connect(progressDialog, &QDialog::rejected, [op]() {
      QObject::disconnect(op, &Operator::progressMessageChanged, nullptr,
                          nullptr);
    });

    connect(op, &Operator::progressMessageChanged, this,
            &ProgressDialogManager::showStatusBarMessage);

    layout->addWidget(progressBar);
  }
  layout->addWidget(progressWidget);
  if (op->supportsCancelingMidTransform()) {
    // Unless the widget has custom progress handling, you can't cancel it.
    QDialogButtonBox* dialogButtons = new QDialogButtonBox(
      QDialogButtonBox::Cancel, Qt::Horizontal, progressDialog);
    layout->addWidget(dialogButtons);
    QObject::connect(progressDialog, &QDialog::rejected, op,
                     &Operator::cancelTransform);
    QObject::connect(dialogButtons, &QDialogButtonBox::rejected, progressDialog,
                     &QDialog::reject);
  }
  progressDialog->setWindowTitle(QString("%1 Progress").arg(op->label()));
  progressDialog->setLayout(layout);
  progressDialog->adjustSize();
  // Increase size of dialog so we can see title, not sure there is a better
  // way.
  auto height = progressDialog->height();
  progressDialog->resize(500, height);
  progressDialog->show();
  QCoreApplication::processEvents();
}

void ProgressDialogManager::operatorAdded(Operator* op)
{
  connect(op, &Operator::transformingStarted, this,
          &ProgressDialogManager::operationStarted,
          Qt::BlockingQueuedConnection);

  connect(op, &Operator::newChildDataSource, this,
          &ProgressDialogManager::dataSourceAdded);
}

void ProgressDialogManager::dataSourceAdded(DataSource* ds)
{
  QObject::connect(ds, SIGNAL(operatorAdded(Operator*)), this,
                   SLOT(operatorAdded(Operator*)));
}

void ProgressDialogManager::operationProgress(int)
{
  // Probably not strictly neccessary in the long run where we have a background
  // thread, until then we need this call.
  QCoreApplication::processEvents();
}

void ProgressDialogManager::showStatusBarMessage(const QString& message)
{
  this->mainWindow->statusBar()->showMessage(message, 3000);
}
}
<|endoftext|>


<commit_before>#include "abstractsessionitem.h"
#include <IrcSession>

AbstractSessionItem::AbstractSessionItem(QObject *parent) :
    QObject(parent), m_session(0), m_current(false), m_highlighted(false), m_unread(false)
{
    m_messages = new QStringListModel(this);
    m_formatter.setTimeStamp(true);
}

IrcSession* AbstractSessionItem::session() const
{
    return m_session;
}

void AbstractSessionItem::setSession(IrcSession *session)
{
    m_session = session;
    m_formatter.setHighlights(QStringList() << session->nickName());
}

QString AbstractSessionItem::title() const
{
    return m_title;
}

void AbstractSessionItem::setTitle(const QString& title)
{
    if (m_title != title)
    {
        m_title = title;
        emit titleChanged();
    }
}

QString AbstractSessionItem::subtitle() const
{
    return m_subtitle;
}

void AbstractSessionItem::setSubtitle(const QString& subtitle)
{
    if (m_subtitle != subtitle)
    {
        m_subtitle = subtitle;
        emit subtitleChanged();
    }
}

bool AbstractSessionItem::isCurrent() const
{
    return m_current;
}

void AbstractSessionItem::setCurrent(bool current)
{
    if (current)
    {
        setHighlighted(false);
        setUnread(0);
    }

    if (m_current != current)
    {
        m_current = current;
        emit currentChanged();
    }
}

bool AbstractSessionItem::isHighlighted() const
{
    return m_highlighted;
}

void AbstractSessionItem::setHighlighted(bool highlighted)
{
    if (!m_current && m_highlighted != highlighted)
    {
        m_highlighted = highlighted;
        emit highlightedChanged();
    }
}

int AbstractSessionItem::unread() const
{
    return m_unread;
}

void AbstractSessionItem::setUnread(int unread)
{
    if (!m_current && m_unread != unread)
    {
        m_unread = unread;
        emit unreadChanged();
    }
}

QStringList AbstractSessionItem::users() const
{
    return m_users;
}

QObject* AbstractSessionItem::messages() const
{
    return m_messages;
}

void AbstractSessionItem::addUser(const QString& user)
{
    m_users.append(user);
    emit usersChanged();
}

void AbstractSessionItem::removeUser(const QString& user)
{
    m_users.removeOne(user);
    emit usersChanged();
}

void AbstractSessionItem::receiveMessage(IrcMessage* message)
{
    const int index = m_messages->rowCount();
    m_messages->insertRow(index);
    m_messages->setData(m_messages->index(index), m_formatter.formatMessage(message));
}
<commit_msg>qml ex: applied formatter colors<commit_after>#include "abstractsessionitem.h"
#include <IrcSession>

AbstractSessionItem::AbstractSessionItem(QObject *parent) :
    QObject(parent), m_session(0), m_current(false), m_highlighted(false), m_unread(false)
{
    m_messages = new QStringListModel(this);
    m_formatter.setTimeStamp(true);
    m_formatter.setEventFormat("style='color:gray'");
    m_formatter.setNoticeFormat("style='color:brown'");
    m_formatter.setActionFormat("style='color:darkmagenta'");
    m_formatter.setUnknownFormat("style='color:brown'");
    m_formatter.setHighlightFormat("style='color:red'");
}

IrcSession* AbstractSessionItem::session() const
{
    return m_session;
}

void AbstractSessionItem::setSession(IrcSession *session)
{
    m_session = session;
    m_formatter.setHighlights(QStringList() << session->nickName());
}

QString AbstractSessionItem::title() const
{
    return m_title;
}

void AbstractSessionItem::setTitle(const QString& title)
{
    if (m_title != title)
    {
        m_title = title;
        emit titleChanged();
    }
}

QString AbstractSessionItem::subtitle() const
{
    return m_subtitle;
}

void AbstractSessionItem::setSubtitle(const QString& subtitle)
{
    if (m_subtitle != subtitle)
    {
        m_subtitle = subtitle;
        emit subtitleChanged();
    }
}

bool AbstractSessionItem::isCurrent() const
{
    return m_current;
}

void AbstractSessionItem::setCurrent(bool current)
{
    if (current)
    {
        setHighlighted(false);
        setUnread(0);
    }

    if (m_current != current)
    {
        m_current = current;
        emit currentChanged();
    }
}

bool AbstractSessionItem::isHighlighted() const
{
    return m_highlighted;
}

void AbstractSessionItem::setHighlighted(bool highlighted)
{
    if (!m_current && m_highlighted != highlighted)
    {
        m_highlighted = highlighted;
        emit highlightedChanged();
    }
}

int AbstractSessionItem::unread() const
{
    return m_unread;
}

void AbstractSessionItem::setUnread(int unread)
{
    if (!m_current && m_unread != unread)
    {
        m_unread = unread;
        emit unreadChanged();
    }
}

QStringList AbstractSessionItem::users() const
{
    return m_users;
}

QObject* AbstractSessionItem::messages() const
{
    return m_messages;
}

void AbstractSessionItem::addUser(const QString& user)
{
    m_users.append(user);
    emit usersChanged();
}

void AbstractSessionItem::removeUser(const QString& user)
{
    m_users.removeOne(user);
    emit usersChanged();
}

void AbstractSessionItem::receiveMessage(IrcMessage* message)
{
    const int index = m_messages->rowCount();
    m_messages->insertRow(index);
    m_messages->setData(m_messages->index(index), m_formatter.formatMessage(message));
}
<|endoftext|>


<commit_before>/*
 * Copyright 2019 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "cleanup.hpp"

#include <blobs-ipmid/blobs.hpp>

#include <filesystem>
#include <memory>
#include <string>
#include <vector>

namespace ipmi_flash
{

std::unique_ptr<blobs::GenericBlobInterface>
    FileCleanupHandler::CreateCleanupHandler(
        const std::string& blobId, const std::vector<std::string>& files)
{
    return std::make_unique<FileCleanupHandler>(blobId, files);
}

bool FileCleanupHandler::canHandleBlob(const std::string& path)
{
    return (path == supported);
}

std::vector<std::string> FileCleanupHandler::getBlobIds()
{
    return {supported};
}

bool FileCleanupHandler::commit(uint16_t session,
                                const std::vector<uint8_t>& data)
{
    namespace fs = std::filesystem;

    for (const auto& file : files)
    {
        helper->remove(file);
    }

    return true;
}

} // namespace ipmi_flash
<commit_msg>cleanup: drop inclusion of unused filesystem header<commit_after>/*
 * Copyright 2019 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "cleanup.hpp"

#include <blobs-ipmid/blobs.hpp>

#include <memory>
#include <string>
#include <vector>

namespace ipmi_flash
{

std::unique_ptr<blobs::GenericBlobInterface>
    FileCleanupHandler::CreateCleanupHandler(
        const std::string& blobId, const std::vector<std::string>& files)
{
    return std::make_unique<FileCleanupHandler>(blobId, files);
}

bool FileCleanupHandler::canHandleBlob(const std::string& path)
{
    return (path == supported);
}

std::vector<std::string> FileCleanupHandler::getBlobIds()
{
    return {supported};
}

bool FileCleanupHandler::commit(uint16_t session,
                                const std::vector<uint8_t>& data)
{
    for (const auto& file : files)
    {
        helper->remove(file);
    }

    return true;
}

} // namespace ipmi_flash
<|endoftext|>


<commit_before>/*******************************************************************************
 * Reverse Polish Notation calculator.                                         *
 * Copyright (c) 2007-2008, Samuel Fredrickson <kinghajj@gmail.com>            *
 * All rights reserved.                                                        *
 *                                                                             *
 * Redistribution and use in source and binary forms, with or without          *
 * modification, are permitted provided that the following conditions are met: *
 *     * Redistributions of source code must retain the above copyright        *
 *       notice, this list of conditions and the following disclaimer.         *
 *     * Redistributions in binary form must reproduce the above copyright     *
 *       notice, this list of conditions and the following disclaimer in the   *
 *       documentation and/or other materials provided with the distribution.  *
 *                                                                             *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``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 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.                                                                     *
 ******************************************************************************/

/*******************************************************************************
 * Calculator.cpp - non-command Calculator methods.                            *
 ******************************************************************************/

#include "rpn.h"
#include <boost/tokenizer.hpp>
#include <sstream>
using namespace boost;
using namespace std;
using namespace RPN;

void Calculator::Eval(string s)
{
    typedef tokenizer< char_separator<char> > Tokens;
    char_separator<char> sep(" \t");
    Tokens tokens(s, sep);

    if(!HasStack()) return;

    for(Tokens::iterator tok = tokens.begin();
        tok != tokens.end() && status == Continue;
        ++tok)
    {
        Commands::iterator foundCommand    = commands.find(*tok);
        Operators::iterator foundOperator  = operators.find(*tok);
        Variables::iterator foundVariable  = variables.find(*tok);
        istringstream iss(*tok);
        Value val;

        // if the token is a number, push it.
        if(iss >> val)
            CurrentStack().push_front(val);

        // if the token is a command, perform it.
        else if(foundCommand != commands.end())
        {
            const Command& command = (*foundCommand).second;
            vector<string> args;
            args.reserve(command.NumArgs());

            // collect a list of tokens that will be the arguments to the
            // command.
            while(tok != tokens.end() && args.size() != command.NumArgs())
                args.push_back(*++tok);

            // only perform a command if we can give it enough arguments.
            if(args.size() == command.NumArgs())
                command.Perform(*this, args);
        }

        // if the token is an operator and that stack has at least two items,
        // then perform that operator.
        else if(foundOperator != operators.end() && StackSize() > 1)
        {
            Value b = TopmostItem(); CurrentStack().pop_front();
            Value a = TopmostItem(); CurrentStack().pop_front();
            CurrentStack().push_front((*foundOperator).second(a, b));
        }

        // if the token is a variable, push the variable onto the stack.
        else if(foundVariable != variables.end())
            CurrentStack().push_front((*foundVariable).second);

        // otherwise, if the stack has at least one item, set a new variable
        // whose name is the token and value is the top item.
        else variables[*tok] = TopmostItem();
    }
}

// displays the top item of the stack if there is one.
// I tried to write this as a friend operator<<(), but I got errors for
// accessing private data, which is what friend functions are supposed to be
// able to do!
void Calculator::Display() const
{
    Print(TopmostItem());
}
<commit_msg>Minor beautificaiton changes.<commit_after>/*******************************************************************************
 * Reverse Polish Notation calculator.                                         *
 * Copyright (c) 2007-2008, Samuel Fredrickson <kinghajj@gmail.com>            *
 * All rights reserved.                                                        *
 *                                                                             *
 * Redistribution and use in source and binary forms, with or without          *
 * modification, are permitted provided that the following conditions are met: *
 *     * Redistributions of source code must retain the above copyright        *
 *       notice, this list of conditions and the following disclaimer.         *
 *     * Redistributions in binary form must reproduce the above copyright     *
 *       notice, this list of conditions and the following disclaimer in the   *
 *       documentation and/or other materials provided with the distribution.  *
 *                                                                             *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``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 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.                                                                     *
 ******************************************************************************/

/*******************************************************************************
 * Calculator.cpp - non-command Calculator methods.                            *
 ******************************************************************************/

#include "rpn.h"
#include <boost/tokenizer.hpp>
#include <sstream>
using namespace boost;
using namespace std;
using namespace RPN;

void Calculator::Eval(string s)
{
    typedef tokenizer< char_separator<char> > Tokens;
    char_separator<char> sep(" \t");
    Tokens tokens(s, sep);

    if(!HasStack()) return;

    for(Tokens::iterator tok = tokens.begin();
        tok != tokens.end() && status == Continue;
        ++tok)
    {
        Commands::iterator foundCommand    = commands.find(*tok);
        Operators::iterator foundOperator  = operators.find(*tok);
        Variables::iterator foundVariable  = variables.find(*tok);
        istringstream iss(*tok);
        Value val;

        // if the token is a number, push it.
        if(iss >> val)
            CurrentStack().push_front(val);

        // if the token is a command, perform it.
        else if(foundCommand != commands.end())
        {
            const Command& command = foundCommand->second;
            vector<string> args;
            args.reserve(command.NumArgs());

            // collect a list of tokens that will be the arguments to the
            // command.
            while(tok != tokens.end() && args.size() != command.NumArgs())
                args.push_back(*++tok);

            // only perform a command if we can give it enough arguments.
            if(args.size() == command.NumArgs())
                command.Perform(*this, args);
        }

        // if the token is an operator and that stack has at least two items,
        // then perform that operator.
        else if(foundOperator != operators.end() && StackSize() > 1)
        {
            Value b = TopmostItem(); CurrentStack().pop_front();
            Value a = TopmostItem(); CurrentStack().pop_front();
            CurrentStack().push_front(foundOperator->second(a, b));
        }

        // if the token is a variable, push the variable onto the stack.
        else if(foundVariable != variables.end())
            CurrentStack().push_front(foundVariable->second);

        // otherwise, if the stack has at least one item, set a new variable
        // whose name is the token and value is the top item.
        else variables[*tok] = TopmostItem();
    }
}

// displays the top item of the stack if there is one.
// I tried to write this as a friend operator<<(), but I got errors for
// accessing private data, which is what friend functions are supposed to be
// able to do!
void Calculator::Display() const
{
    Print(TopmostItem());
}
<|endoftext|>


<commit_before>/* Copyright 2007-2015 QReal Research Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. */

#include "pointsQueueProcessor.h"

using namespace utils::sensorsGraph;

PointsQueueProcessor::PointsQueueProcessor(const qreal viewPortHeight, const qreal leftLimit)
	: mMinCurrent(0)
	, mMaxCurrent(1)
	, mNextToDraw(QPointF(0, -80))
{
	setViewParams(viewPortHeight, leftLimit);
}

PointsQueueProcessor::~PointsQueueProcessor()
{
	mPointsQueue.clear();
}

void PointsQueueProcessor::addNewValue(const qreal newValue)
{
	const qreal oldMax = mMaxCurrent;
	const qreal oldMin = mMinCurrent;
	if (newValue > mMaxCurrent) {
		mMaxCurrent = newValue;
	}

	if (newValue < mMinCurrent) {
		mMinCurrent = newValue;
	}

	if (oldMax != mMaxCurrent || oldMin != mMinCurrent) {
		recalcPointsQueue(oldMin, oldMax, mGraphHeight);
	}

	mNextToDraw.setY(absoluteValueToPoint(newValue));
	filterLastValues();
	mPointsQueue.append(QPointF(0, absoluteValueToPoint(newValue)));
}

void PointsQueueProcessor::recalcPointsQueue(const qreal oldMin, const qreal oldMax, const qreal oldViewHeight)
{
	qreal currentValue = 0;
	for (int i = 0; i < mPointsQueue.size(); i++) {
		currentValue = pointToAbsoluteValue(mPointsQueue[i].y(), oldMin, oldMax, oldViewHeight);
		mPointsQueue[i].setY(absoluteValueToPoint(currentValue));
	}
}

void PointsQueueProcessor::filterLastValues()
{
	if (mPointsQueue.size() < 2) {
		return;
	}

	const qreal filterPixelDiff = 2;
	if (qAbs(mPointsQueue.at(mPointsQueue.size() - 2).y() - mPointsQueue.last().y()) < filterPixelDiff) {
		mPointsQueue.removeLast();
	}
}

void PointsQueueProcessor::makeShiftLeft(const qreal step)
{
	mPointsQueue.append(latestPosition());
	for (int i = 0; i < mPointsQueue.size(); i++) {
		mPointsQueue[i].setX(mPointsQueue[i].x() - step);
		if (mPointsQueue[i].x() < mLeftLimit) {
			mPointsQueue.removeAt(i--);
		}
	}
}

qreal PointsQueueProcessor::absoluteValueToPoint(const qreal value) const
{
	const int verticalBounds = 10;
	const int invertCoordSys = -1;
	return ((value - mMinCurrent) / (mMaxCurrent - mMinCurrent) * mGraphHeight + verticalBounds) * invertCoordSys;
}

qreal PointsQueueProcessor::pointToAbsoluteValue(const qreal yValue) const
{
	return pointToAbsoluteValue(yValue, mMinCurrent, mMaxCurrent, mGraphHeight);
}

qreal PointsQueueProcessor::pointToAbsoluteValue(const qreal yValue, const qreal minValue
		, const qreal maxValue, const qreal graphHeight) const
{
	return (((maxValue - minValue) * (-yValue - 10)) / graphHeight) + minValue;
}

void PointsQueueProcessor::clearData()
{
	mMinCurrent = 0;
	mMaxCurrent = 1;
	mPointsQueue.clear();
}

QPointF PointsQueueProcessor::latestPosition() const
{
	return mNextToDraw;
}

qreal PointsQueueProcessor::latestValue() const
{
	return pointToAbsoluteValue(mNextToDraw.y(), mMinCurrent, mMaxCurrent, mGraphHeight);
}

const QList<QPointF> &PointsQueueProcessor::pointsBase() const
{
	return mPointsQueue;
}

void PointsQueueProcessor::checkPeaks()
{
	const qreal oldMin = mMinCurrent;
	const qreal oldMax = mMaxCurrent;

	mMaxCurrent = std::numeric_limits<qreal>::min();
	mMinCurrent = std::numeric_limits<qreal>::max();

	for (int i = 0; i < mPointsQueue.size(); i++) {
		if (pointToAbsoluteValue(mPointsQueue[i].y(), oldMin, oldMax, mGraphHeight) > mMaxCurrent) {
			mMaxCurrent = pointToAbsoluteValue(mPointsQueue[i].y(), oldMin, oldMax, mGraphHeight);
		}
		if (pointToAbsoluteValue(mPointsQueue[i].y(), oldMin, oldMax, mGraphHeight) < mMinCurrent) {
			mMinCurrent = pointToAbsoluteValue(mPointsQueue[i].y(), oldMin, oldMax, mGraphHeight);
		}
	}

	recalcPointsQueue(oldMin, oldMax, mGraphHeight);
}

QPointF PointsQueueProcessor::pointOfVerticalIntersection(const QPointF &position) const
{
	if (mPointsQueue.isEmpty())
		return QPointF(0, 0);
	const qreal accuracyCoefficient = 2; // accuracy = diameter * accCoefficient
	const qreal diameter = (mPointsQueue.last().x() - mPointsQueue.first().x()) / mPointsQueue.size();

	QPointF result;
	int leftBound = 0;
	int rightBound = mPointsQueue.size() - 1;
	while (leftBound < rightBound) {
		int middleIndex = (rightBound + leftBound) / 2;
		result = mPointsQueue.at(middleIndex);
		if (qAbs(result.x() - position.x()) < diameter * accuracyCoefficient) {
			break;
		}

		if (position.x() < result.x()) {
			rightBound = middleIndex - 1;
		}

		if (position.x() > result.x()) {
			leftBound = middleIndex + 1;
		}
	}

	return result;
}

void PointsQueueProcessor::setViewParams(const qreal viewPortHeight, const qreal leftLimit)
{
	const qreal oldViewHeight = mGraphHeight;
	mGraphHeight = viewPortHeight;
	recalcPointsQueue(mMinCurrent, mMaxCurrent, oldViewHeight);
	mLeftLimit = leftLimit;
}

qreal PointsQueueProcessor::minLimit() const
{
	return mMinCurrent;
}

qreal PointsQueueProcessor::maxLimit() const
{
	return mMaxCurrent;
}
<commit_msg>Fixed #1636<commit_after>/* Copyright 2007-2015 QReal Research Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. */

#include "pointsQueueProcessor.h"

using namespace utils::sensorsGraph;

PointsQueueProcessor::PointsQueueProcessor(const qreal viewPortHeight, const qreal leftLimit)
	: mMinCurrent(0)
	, mMaxCurrent(1)
	, mNextToDraw(QPointF(0, -80))
{
	setViewParams(viewPortHeight, leftLimit);
}

PointsQueueProcessor::~PointsQueueProcessor()
{
	mPointsQueue.clear();
}

void PointsQueueProcessor::addNewValue(const qreal newValue)
{
	const qreal oldMax = mMaxCurrent;
	const qreal oldMin = mMinCurrent;
	if (newValue > mMaxCurrent) {
		mMaxCurrent = newValue;
	}

	if (newValue < mMinCurrent) {
		mMinCurrent = newValue;
	}

	if (oldMax != mMaxCurrent || oldMin != mMinCurrent) {
		recalcPointsQueue(oldMin, oldMax, mGraphHeight);
	}

	mNextToDraw.setY(absoluteValueToPoint(newValue));
	filterLastValues();
	mPointsQueue.append(QPointF(0, absoluteValueToPoint(newValue)));
}

void PointsQueueProcessor::recalcPointsQueue(const qreal oldMin, const qreal oldMax, const qreal oldViewHeight)
{
	qreal currentValue = 0;
	for (int i = 0; i < mPointsQueue.size(); i++) {
		currentValue = pointToAbsoluteValue(mPointsQueue[i].y(), oldMin, oldMax, oldViewHeight);
		mPointsQueue[i].setY(absoluteValueToPoint(currentValue));
	}
}

void PointsQueueProcessor::filterLastValues()
{
	if (mPointsQueue.size() < 2) {
		return;
	}

	const qreal filterPixelDiff = 2;
	if (qAbs(mPointsQueue.at(mPointsQueue.size() - 2).y() - mPointsQueue.last().y()) < filterPixelDiff) {
		mPointsQueue.removeLast();
	}
}

void PointsQueueProcessor::makeShiftLeft(const qreal step)
{
	mPointsQueue.append(latestPosition());
	for (int i = 0; i < mPointsQueue.size(); i++) {
		mPointsQueue[i].setX(mPointsQueue[i].x() - step);
		if (mPointsQueue[i].x() < mLeftLimit) {
			mPointsQueue.removeAt(i--);
		}
	}
}

qreal PointsQueueProcessor::absoluteValueToPoint(const qreal value) const
{
	const int verticalBounds = 10;
	const int invertCoordSys = -1;
	if (qFuzzyCompare(mMaxCurrent, mMinCurrent)) {
		return mNextToDraw.y();
	}

	return ((value - mMinCurrent) / (mMaxCurrent - mMinCurrent) * mGraphHeight + verticalBounds) * invertCoordSys;
}

qreal PointsQueueProcessor::pointToAbsoluteValue(const qreal yValue) const
{
	return pointToAbsoluteValue(yValue, mMinCurrent, mMaxCurrent, mGraphHeight);
}

qreal PointsQueueProcessor::pointToAbsoluteValue(const qreal yValue, const qreal minValue
		, const qreal maxValue, const qreal graphHeight) const
{
	return (((maxValue - minValue) * (-yValue - 10)) / graphHeight) + minValue;
}

void PointsQueueProcessor::clearData()
{
	mMinCurrent = 0;
	mMaxCurrent = 1;
	mPointsQueue.clear();
}

QPointF PointsQueueProcessor::latestPosition() const
{
	return mNextToDraw;
}

qreal PointsQueueProcessor::latestValue() const
{
	return pointToAbsoluteValue(mNextToDraw.y(), mMinCurrent, mMaxCurrent, mGraphHeight);
}

const QList<QPointF> &PointsQueueProcessor::pointsBase() const
{
	return mPointsQueue;
}

void PointsQueueProcessor::checkPeaks()
{
	const qreal oldMin = mMinCurrent;
	const qreal oldMax = mMaxCurrent;

	mMaxCurrent = std::numeric_limits<qreal>::min();
	mMinCurrent = std::numeric_limits<qreal>::max();

	for (int i = 0; i < mPointsQueue.size(); i++) {
		if (pointToAbsoluteValue(mPointsQueue[i].y(), oldMin, oldMax, mGraphHeight) > mMaxCurrent) {
			mMaxCurrent = pointToAbsoluteValue(mPointsQueue[i].y(), oldMin, oldMax, mGraphHeight);
		}
		if (pointToAbsoluteValue(mPointsQueue[i].y(), oldMin, oldMax, mGraphHeight) < mMinCurrent) {
			mMinCurrent = pointToAbsoluteValue(mPointsQueue[i].y(), oldMin, oldMax, mGraphHeight);
		}
	}

	recalcPointsQueue(oldMin, oldMax, mGraphHeight);
}

QPointF PointsQueueProcessor::pointOfVerticalIntersection(const QPointF &position) const
{
	if (mPointsQueue.isEmpty())
		return QPointF(0, 0);
	const qreal accuracyCoefficient = 2; // accuracy = diameter * accCoefficient
	const qreal diameter = (mPointsQueue.last().x() - mPointsQueue.first().x()) / mPointsQueue.size();

	QPointF result;
	int leftBound = 0;
	int rightBound = mPointsQueue.size() - 1;
	while (leftBound < rightBound) {
		int middleIndex = (rightBound + leftBound) / 2;
		result = mPointsQueue.at(middleIndex);
		if (qAbs(result.x() - position.x()) < diameter * accuracyCoefficient) {
			break;
		}

		if (position.x() < result.x()) {
			rightBound = middleIndex - 1;
		}

		if (position.x() > result.x()) {
			leftBound = middleIndex + 1;
		}
	}

	return result;
}

void PointsQueueProcessor::setViewParams(const qreal viewPortHeight, const qreal leftLimit)
{
	const qreal oldViewHeight = mGraphHeight;
	mGraphHeight = viewPortHeight;
	recalcPointsQueue(mMinCurrent, mMaxCurrent, oldViewHeight);
	mLeftLimit = leftLimit;
}

qreal PointsQueueProcessor::minLimit() const
{
	return mMinCurrent;
}

qreal PointsQueueProcessor::maxLimit() const
{
	return mMaxCurrent;
}
<|endoftext|>


<commit_before>/*
 * (C) Copyright 2014 Kurento (http://kurento.org/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "logging.hpp"

#include <gst/gst.h>

#include <boost/format.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/sources/channel_feature.hpp>
#include <boost/log/sources/channel_logger.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/manipulators/add_value.hpp>
#include <sys/types.h>
#include <unistd.h>

namespace logging = boost::log;
namespace attrs = boost::log::attributes;
namespace src = boost::log::sources;
namespace sinks = boost::log::sinks;
namespace expr = boost::log::expressions;
namespace keywords = boost::log::keywords;

typedef sinks::synchronous_sink< sinks::text_file_backend > sink_t;

namespace kurento
{

// ----------------------------------------------------------------------------

GST_DEBUG_CATEGORY_STATIC (kms_glib_debug);

static GstDebugLevel
g_log_level_to_gst_debug_level (GLogLevelFlags log_level)
{
  switch (log_level & G_LOG_LEVEL_MASK) {
  case G_LOG_LEVEL_ERROR:    return GST_LEVEL_ERROR;
  case G_LOG_LEVEL_CRITICAL: return GST_LEVEL_ERROR;
  case G_LOG_LEVEL_WARNING:  return GST_LEVEL_WARNING;
  case G_LOG_LEVEL_MESSAGE:  return GST_LEVEL_FIXME;
  case G_LOG_LEVEL_INFO:     return GST_LEVEL_INFO;
  case G_LOG_LEVEL_DEBUG:    return GST_LEVEL_DEBUG;
  default:                   return GST_LEVEL_DEBUG;
  }
}

/*
 * Based on the Glib 2.48.2 default message handler, g_log_default_handler()
 * https://github.com/GNOME/glib/blob/2.48.2/glib/gmessages.c#L1429
 *
 * NOTE: In Glib 2.50 they added a new logging mode, "structured logging", that
 * maybe we need to check out in the future.
 */
/* these are emitted by the default log handler */
#define DEFAULT_LEVELS (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE)
/* these are filtered by G_MESSAGES_DEBUG by the default log handler */
#define INFO_LEVELS (G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG)
static void
kms_glib_log_handler (const gchar   *log_domain,
                      GLogLevelFlags log_level,
                      const gchar   *message,
                      gpointer       unused_data)
{
  const gchar *domains;

  if ((log_level & DEFAULT_LEVELS) || (log_level >> G_LOG_LEVEL_USER_SHIFT)) {
    goto emit;
  }

  domains = g_getenv ("G_MESSAGES_DEBUG");
  if (((log_level & INFO_LEVELS) == 0) ||
      domains == NULL ||
      (strcmp (domains, "all") != 0 && (!log_domain || !strstr (domains, log_domain))))
  {
    return;
  }

 emit:
  /* we can be called externally with recursion for whatever reason */
  if (log_level & G_LOG_FLAG_RECURSION)
    {
      //_g_log_fallback_handler (log_domain, log_level, message, unused_data);
      return;
    }

  // Forward Glib log messages through GStreamer logging

  GstDebugCategory *category = kms_glib_debug;
  GstDebugLevel level = g_log_level_to_gst_debug_level (log_level);
  const gchar *file = log_domain;
  const gchar *function = "";
  gint line = 0;
  GObject *object = NULL;

  if (!message) {
    gst_debug_log (category, level, file, function, line, object, "%s",
        "(NULL) message");
  } else {
    gst_debug_log (category, level, file, function, line, object, "%s",
        message);
  }
}

void
kms_init_logging ()
{
  // Forward Glib log messages through GStreamer logging
  GST_DEBUG_CATEGORY_INIT (kms_glib_debug, "glib", 0, "Glib logging");
  g_log_set_default_handler (kms_glib_log_handler, NULL);
}

// ----------------------------------------------------------------------------

/* kurento logging sinks */
boost::shared_ptr< sink_t > system_sink;

static std::string
debug_object (GObject *object)
{
  if (object == nullptr) {
    return "";
  }

  if (GST_IS_PAD (object) && GST_OBJECT_NAME (object) ) {
    boost::format fmt ("<%s:%s> ");
    fmt %
        (GST_OBJECT_PARENT(object) != nullptr
             ? GST_OBJECT_NAME(GST_OBJECT_PARENT(object))
             : "''") %
        GST_OBJECT_NAME(object);
    return fmt.str();
  }

  if (GST_IS_OBJECT (object) && GST_OBJECT_NAME (object) ) {
    boost::format fmt ("<%s> ");
    fmt % GST_OBJECT_NAME (object);
    return fmt.str();
  }

  if (G_IS_OBJECT (object) ) {
    boost::format fmt ("<%s@%p> ");
    fmt %  G_OBJECT_TYPE_NAME (object) % object;
    return fmt.str();
  }

  boost::format fmt ("<%p> ");
  fmt % object;
  return fmt.str();
}

static std::string
expand_string (std::string str, int len)
{
  std::string ret = str;
  int sp = len - str.size ();

  for (int i = sp; i > 0; i--) {
    str.append (" ");
  }

  return str;
}

static severity_level
gst_debug_level_to_severity_level (GstDebugLevel level)
{
  switch (level) {
  case GST_LEVEL_ERROR:   return error;
  case GST_LEVEL_WARNING: return warning;
  case GST_LEVEL_FIXME:   return fixme;
  case GST_LEVEL_INFO:    return info;
  case GST_LEVEL_DEBUG:   return debug;
  case GST_LEVEL_LOG:     return log;
  case GST_LEVEL_TRACE:   return trace;
  default:                return undefined;
  }
}

static void
kms_log_function (GstDebugCategory *category, GstDebugLevel level,
                  const gchar *file,
                  const gchar *function, gint line, GObject *object,
                  GstDebugMessage *message, gpointer user_data) G_GNUC_NO_INSTRUMENT;

static void
kms_log_function (GstDebugCategory *category, GstDebugLevel level,
                  const gchar *file,
                  const gchar *function, gint line, GObject *object,
                  GstDebugMessage *message, gpointer user_data)
{
  if (level > gst_debug_category_get_threshold (category) ) {
    return;
  }

  severity_level severity = gst_debug_level_to_severity_level (level);

  if (severity == undefined) {
    return;
  }

  BOOST_LOG_SEV (system_logger::get(), severity) <<
      logging::add_value ("Category", expand_string (category->name, 25) ) <<
      logging::add_value ("FileName",
                          boost::filesystem::path (file).filename().string() ) <<
      logging::add_value ("Line", line) <<
      logging::add_value ("Function", function) <<
      logging::add_value ("GObject", debug_object (object) ) <<
      gst_debug_message_get (message);
}

void init_file_collecting (boost::shared_ptr< sink_t > sink,
                           const std::string &path,
                           int fileSize,
                           int fileNumber)
{
  sink->locked_backend()->set_file_collector (sinks::file::make_collector (
        keywords::target = path,
        keywords::max_size = (fileSize * fileNumber) * 1024 * 1024,
        keywords::min_free_space = fileSize * 1024 * 1024
      ) );
}

/* The formatting logic for the severity level */
template< typename CharT, typename TraitsT >
inline std::basic_ostream< CharT, TraitsT > &operator<< (
  std::basic_ostream< CharT, TraitsT > &strm, severity_level lvl)
{
  static const char *const str[] = {
    "  error",
    "warning",
    "  fixme",
    "   info",
    "  debug",
    "    log",
    "  trace",
    "unknown"
  };

  if (static_cast< std::size_t > (lvl) < (sizeof (str) / sizeof (*str) ) ) {
    strm << str[lvl];
  } else {
    strm << static_cast< int > (lvl);
  }

  return strm;
}

static void
system_formatter (logging::record_view const &rec,
                  logging::formatting_ostream &strm)
{
  auto date_time_formatter = expr::stream
                             << expr::format_date_time< boost::posix_time::ptime > ("TimeStamp",
                                 "%Y-%m-%dT%H:%M:%S,%f");
  date_time_formatter (rec, strm) << " ";
  strm << std::to_string (getpid() ) << " ";
  strm << logging::extract< attrs::current_thread_id::value_type > ("ThreadID",
           rec) << " ";
  strm << logging::extract< severity_level > ("Severity", rec) << " ";
  strm << logging::extract< std::string > ("Category", rec) << " ";
  strm << logging::extract< std::string > ("FileName", rec) << ":";
  strm << logging::extract< int > ("Line", rec) << " ";
  strm << logging::extract< std::string > ("Function", rec) << "() ";
  strm << logging::extract< std::string > ("GObject", rec) << " ";
  strm << rec[expr::smessage];
}

bool
kms_init_logging_files (const std::string &path, int fileSize, int fileNumber)
{
  gst_debug_remove_log_function (gst_debug_log_default);
  gst_debug_add_log_function(kms_log_function, nullptr, nullptr);

  boost::shared_ptr< logging::core > core = logging::core::get();

  boost::shared_ptr< sinks::text_file_backend > backend =
    boost::make_shared< sinks::text_file_backend > (
      keywords::file_name = path + "/" + "%Y-%m-%dT%H%M%S.%5N.pid" +
                            std::to_string (getpid() ) + ".log",
      keywords::rotation_size = fileSize * 1024 * 1024,
      keywords::time_based_rotation = sinks::file::rotation_at_time_point (0, 0, 0)
    );

  /* Enable auto-flushing after each log record written */
  backend->auto_flush (true);

  /* Wrap it into the frontend and register in the core.   */
  /* The backend requires synchronization in the frontend. */
  system_sink = boost::shared_ptr< sink_t > (new sink_t (backend) );

  /*Set up filter to pass only records that have the necessary attributes */
  system_sink->set_filter (
    expr::has_attr< std::string > ("Channel") &&
    expr::attr< std::string > ("Channel") == "system"
  );

  /* Set up where the rotated files will be stored */
  init_file_collecting (system_sink, path, fileSize, fileNumber);

  /* Upon restart, scan the directory for files matching the file_name pattern */
  system_sink->locked_backend()->scan_for_files();

  core->add_sink (system_sink);

  system_sink->set_formatter (&system_formatter);

  return true;
}

// ----------------------------------------------------------------------------

}  /* kurento */
<commit_msg>Logging: Fix NULL reference (use default value)<commit_after>/*
 * (C) Copyright 2014 Kurento (http://kurento.org/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "logging.hpp"

#include <gst/gst.h>

#include <boost/format.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/sources/channel_feature.hpp>
#include <boost/log/sources/channel_logger.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/manipulators/add_value.hpp>
#include <sys/types.h>
#include <unistd.h>

namespace logging = boost::log;
namespace attrs = boost::log::attributes;
namespace src = boost::log::sources;
namespace sinks = boost::log::sinks;
namespace expr = boost::log::expressions;
namespace keywords = boost::log::keywords;

typedef sinks::synchronous_sink< sinks::text_file_backend > sink_t;

namespace kurento
{

// ----------------------------------------------------------------------------

GST_DEBUG_CATEGORY_STATIC (kms_glib_debug);

static GstDebugLevel
g_log_level_to_gst_debug_level (GLogLevelFlags log_level)
{
  switch (log_level & G_LOG_LEVEL_MASK) {
  case G_LOG_LEVEL_ERROR:    return GST_LEVEL_ERROR;
  case G_LOG_LEVEL_CRITICAL: return GST_LEVEL_ERROR;
  case G_LOG_LEVEL_WARNING:  return GST_LEVEL_WARNING;
  case G_LOG_LEVEL_MESSAGE:  return GST_LEVEL_FIXME;
  case G_LOG_LEVEL_INFO:     return GST_LEVEL_INFO;
  case G_LOG_LEVEL_DEBUG:    return GST_LEVEL_DEBUG;
  default:                   return GST_LEVEL_DEBUG;
  }
}

/*
 * Based on the Glib 2.48.2 default message handler, g_log_default_handler()
 * https://github.com/GNOME/glib/blob/2.48.2/glib/gmessages.c#L1429
 *
 * NOTE: In Glib 2.50 they added a new logging mode, "structured logging", that
 * maybe we need to check out in the future.
 */
/* these are emitted by the default log handler */
#define DEFAULT_LEVELS (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE)
/* these are filtered by G_MESSAGES_DEBUG by the default log handler */
#define INFO_LEVELS (G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG)
static void
kms_glib_log_handler (const gchar   *log_domain,
                      GLogLevelFlags log_level,
                      const gchar   *message,
                      gpointer       unused_data)
{
  const gchar *domains;

  if ((log_level & DEFAULT_LEVELS) || (log_level >> G_LOG_LEVEL_USER_SHIFT)) {
    goto emit;
  }

  domains = g_getenv ("G_MESSAGES_DEBUG");
  if (((log_level & INFO_LEVELS) == 0) ||
      domains == NULL ||
      (strcmp (domains, "all") != 0 && (!log_domain || !strstr (domains, log_domain))))
  {
    return;
  }

 emit:
  /* we can be called externally with recursion for whatever reason */
  if (log_level & G_LOG_FLAG_RECURSION)
    {
      //_g_log_fallback_handler (log_domain, log_level, message, unused_data);
      return;
    }

  // Forward Glib log messages through GStreamer logging

  GstDebugCategory *category = kms_glib_debug;
  GstDebugLevel level = g_log_level_to_gst_debug_level (log_level);
  const gchar *file = log_domain ? log_domain : "(NULL domain)";
  const gchar *function = "";
  gint line = 0;
  GObject *object = NULL;

  if (!message) {
    gst_debug_log (category, level, file, function, line, object, "%s",
        "(NULL message)");
  } else {
    gst_debug_log (category, level, file, function, line, object, "%s",
        message);
  }
}

void
kms_init_logging ()
{
  // Forward Glib log messages through GStreamer logging
  GST_DEBUG_CATEGORY_INIT (kms_glib_debug, "glib", 0, "Glib logging");
  g_log_set_default_handler (kms_glib_log_handler, NULL);
}

// ----------------------------------------------------------------------------

/* kurento logging sinks */
boost::shared_ptr< sink_t > system_sink;

static std::string
debug_object (GObject *object)
{
  if (object == nullptr) {
    return "";
  }

  if (GST_IS_PAD (object) && GST_OBJECT_NAME (object) ) {
    boost::format fmt ("<%s:%s> ");
    fmt %
        (GST_OBJECT_PARENT(object) != nullptr
             ? GST_OBJECT_NAME(GST_OBJECT_PARENT(object))
             : "''") %
        GST_OBJECT_NAME(object);
    return fmt.str();
  }

  if (GST_IS_OBJECT (object) && GST_OBJECT_NAME (object) ) {
    boost::format fmt ("<%s> ");
    fmt % GST_OBJECT_NAME (object);
    return fmt.str();
  }

  if (G_IS_OBJECT (object) ) {
    boost::format fmt ("<%s@%p> ");
    fmt %  G_OBJECT_TYPE_NAME (object) % object;
    return fmt.str();
  }

  boost::format fmt ("<%p> ");
  fmt % object;
  return fmt.str();
}

static std::string
expand_string (std::string str, int len)
{
  std::string ret = str;
  int sp = len - str.size ();

  for (int i = sp; i > 0; i--) {
    str.append (" ");
  }

  return str;
}

static severity_level
gst_debug_level_to_severity_level (GstDebugLevel level)
{
  switch (level) {
  case GST_LEVEL_ERROR:   return error;
  case GST_LEVEL_WARNING: return warning;
  case GST_LEVEL_FIXME:   return fixme;
  case GST_LEVEL_INFO:    return info;
  case GST_LEVEL_DEBUG:   return debug;
  case GST_LEVEL_LOG:     return log;
  case GST_LEVEL_TRACE:   return trace;
  default:                return undefined;
  }
}

static void
kms_log_function (GstDebugCategory *category, GstDebugLevel level,
                  const gchar *file,
                  const gchar *function, gint line, GObject *object,
                  GstDebugMessage *message, gpointer user_data) G_GNUC_NO_INSTRUMENT;

static void
kms_log_function (GstDebugCategory *category, GstDebugLevel level,
                  const gchar *file,
                  const gchar *function, gint line, GObject *object,
                  GstDebugMessage *message, gpointer user_data)
{
  if (level > gst_debug_category_get_threshold (category) ) {
    return;
  }

  severity_level severity = gst_debug_level_to_severity_level (level);

  if (severity == undefined) {
    return;
  }

  BOOST_LOG_SEV (system_logger::get(), severity) <<
      logging::add_value ("Category", expand_string (category->name, 25) ) <<
      logging::add_value ("FileName",
                          boost::filesystem::path (file).filename().string() ) <<
      logging::add_value ("Line", line) <<
      logging::add_value ("Function", function) <<
      logging::add_value ("GObject", debug_object (object) ) <<
      gst_debug_message_get (message);
}

void init_file_collecting (boost::shared_ptr< sink_t > sink,
                           const std::string &path,
                           int fileSize,
                           int fileNumber)
{
  sink->locked_backend()->set_file_collector (sinks::file::make_collector (
        keywords::target = path,
        keywords::max_size = (fileSize * fileNumber) * 1024 * 1024,
        keywords::min_free_space = fileSize * 1024 * 1024
      ) );
}

/* The formatting logic for the severity level */
template< typename CharT, typename TraitsT >
inline std::basic_ostream< CharT, TraitsT > &operator<< (
  std::basic_ostream< CharT, TraitsT > &strm, severity_level lvl)
{
  static const char *const str[] = {
    "  error",
    "warning",
    "  fixme",
    "   info",
    "  debug",
    "    log",
    "  trace",
    "unknown"
  };

  if (static_cast< std::size_t > (lvl) < (sizeof (str) / sizeof (*str) ) ) {
    strm << str[lvl];
  } else {
    strm << static_cast< int > (lvl);
  }

  return strm;
}

static void
system_formatter (logging::record_view const &rec,
                  logging::formatting_ostream &strm)
{
  auto date_time_formatter = expr::stream
                             << expr::format_date_time< boost::posix_time::ptime > ("TimeStamp",
                                 "%Y-%m-%dT%H:%M:%S,%f");
  date_time_formatter (rec, strm) << " ";
  strm << std::to_string (getpid() ) << " ";
  strm << logging::extract< attrs::current_thread_id::value_type > ("ThreadID",
           rec) << " ";
  strm << logging::extract< severity_level > ("Severity", rec) << " ";
  strm << logging::extract< std::string > ("Category", rec) << " ";
  strm << logging::extract< std::string > ("FileName", rec) << ":";
  strm << logging::extract< int > ("Line", rec) << " ";
  strm << logging::extract< std::string > ("Function", rec) << "() ";
  strm << logging::extract< std::string > ("GObject", rec) << " ";
  strm << rec[expr::smessage];
}

bool
kms_init_logging_files (const std::string &path, int fileSize, int fileNumber)
{
  gst_debug_remove_log_function (gst_debug_log_default);
  gst_debug_add_log_function(kms_log_function, nullptr, nullptr);

  boost::shared_ptr< logging::core > core = logging::core::get();

  boost::shared_ptr< sinks::text_file_backend > backend =
    boost::make_shared< sinks::text_file_backend > (
      keywords::file_name = path + "/" + "%Y-%m-%dT%H%M%S.%5N.pid" +
                            std::to_string (getpid() ) + ".log",
      keywords::rotation_size = fileSize * 1024 * 1024,
      keywords::time_based_rotation = sinks::file::rotation_at_time_point (0, 0, 0)
    );

  /* Enable auto-flushing after each log record written */
  backend->auto_flush (true);

  /* Wrap it into the frontend and register in the core.   */
  /* The backend requires synchronization in the frontend. */
  system_sink = boost::shared_ptr< sink_t > (new sink_t (backend) );

  /*Set up filter to pass only records that have the necessary attributes */
  system_sink->set_filter (
    expr::has_attr< std::string > ("Channel") &&
    expr::attr< std::string > ("Channel") == "system"
  );

  /* Set up where the rotated files will be stored */
  init_file_collecting (system_sink, path, fileSize, fileNumber);

  /* Upon restart, scan the directory for files matching the file_name pattern */
  system_sink->locked_backend()->scan_for_files();

  core->add_sink (system_sink);

  system_sink->set_formatter (&system_formatter);

  return true;
}

// ----------------------------------------------------------------------------

}  /* kurento */
<|endoftext|>