Skip to content

Commit

Permalink
Add partial output; Add interface through arguments; Add character ou…
Browse files Browse the repository at this point in the history
…tput
  • Loading branch information
skapix committed Aug 26, 2017
1 parent b0440b2 commit cc6487c
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 35 deletions.
2 changes: 1 addition & 1 deletion cohbcalc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ set(sources cohbcalc.cpp ConsoleHandler.cpp ConsoleHandler.h KeyHandler.h
if (WIN32)
set(sources ${sources} WindowsKeyHandler.cpp)
elseif (UNIX AND NOT APPLE)
set(sources ${sources} LinuxKeyHandler.cpp)
set(sources ${sources} LinuxKeyHandler.cpp OutputRepresentation.cpp OutputRepresentation.h)
else()
message(WARNING "cohbcalc does not support this system. Project cohbcalc is disabled")
return()
Expand Down
138 changes: 138 additions & 0 deletions cohbcalc/OutputRepresentation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#include "OutputRepresentation.h"
#include "ohbTransform.h"
#include <sstream>
#include <iomanip>
#include <iostream>

using namespace std;



namespace
{

const string g_outputName = "Output";

string printChars(const int64_t result)
{
ostringstream buffer;
auto stringResult = toChars(result);
for (char character : stringResult)
{
if (isprint(character))
{
buffer << character;
continue;
}
int value = static_cast<int>(static_cast<unsigned char>(character));

buffer << '\\' << setfill('0') << setw(2) << hex << value;
}

return buffer.str();
}

} // namespace

OutputRepresentation::OutputRepresentation()
{
m_outputs.push_back({'d', [](int64_t result) {return std::to_string(result);}});
m_outputs.push_back({'h', [](int64_t result) {return toHex(result);}});
m_outputs.push_back({'o', [](int64_t result) {return toOctal(result);}});
m_outputs.push_back({'c', printChars});
m_outputs.push_back({'b', [](int64_t result) {return toBinary(result);}});
}

void OutputRepresentation::printResult(int64_t result)
{
for (auto it : m_outputs)
{
if (!it.isActive)
{
continue;
}
cout << it.character << ": " << it.function(result) << endl;
}
}


bool OutputRepresentation::handleLetter(char letter, bool value)
{
// going to handle only visible characters
if (!isprint(letter) || isspace(letter))
{
return false;
}
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
[letter](const RepresentationInfo &info) {return info.character == letter;});
if (it == m_outputs.end())
{
cerr << "No representation for letter '" << letter << "' found" << endl;
return false;
}
it->isActive = value;
return false;
}

static bool isOutputReprSettings(const string& expression)
{
if (expression.size() < g_outputName.size())
{
return false;
}
for (size_t i = 0; i < g_outputName.size(); ++i)
{
if (tolower(g_outputName[i]) != tolower(expression[i]))
{
return false;
}
}

return true;
}

bool OutputRepresentation::parseOutputSettings(const std::string &settings) {

if (!isOutputReprSettings(settings))
{
return false;
}

enum
{
Undefined, Set, Append, Subtract
} settingType = Undefined;
size_t startPos = g_outputName.size();

if (settings[startPos] == '=')
{
settingType = Set;
++startPos;
} else if (settings[startPos] == '+' && settings[startPos + 1] == '=') {
settingType = Append;
startPos += 2;
} else if (settings[startPos] == '-' && settings[startPos + 1] == '=') {
settingType = Subtract;
startPos += 2;
} else {
return false;
}
assert(settingType != Undefined);

if (settingType == Set)
{
for (auto &it : m_outputs)
{
it.isActive = false;
}
settingType = Append;
}

for (; startPos < settings.size(); ++startPos)
{
handleLetter(settings[startPos], settingType == Append);
}

return true;
}

24 changes: 24 additions & 0 deletions cohbcalc/OutputRepresentation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once
#include <cstdint>
#include <string>
#include <functional>

class OutputRepresentation
{
public:
OutputRepresentation();
void printResult(int64_t result);
bool parseOutputSettings(const std::string &settings);

private:
bool handleLetter(char letter, bool value);

private:
struct RepresentationInfo
{
const char character;
const std::function<std::string(int64_t)> function;
bool isActive = true;
};
std::vector<RepresentationInfo> m_outputs;
};
93 changes: 61 additions & 32 deletions cohbcalc/cohbcalc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,39 @@
#include "ohbTransform.h"
#include "ohbException.h"
#include "ConsoleHandler.h"
#include "OutputRepresentation.h"

#include <iostream>
#include <set>
#include <iomanip>

using namespace std;

namespace {

struct InitConsole
{
InitConsole() { initConsole(); }

~InitConsole() { deinitConsole(); }
};

static bool isExitSequence(const string &str)
{
bool isExitSequence(const string &str) {
const set<string> exitSequence = {"q", "quit", "exit", "Exit"};
return exitSequence.find(str) != exitSequence.end();
}

const static string g_inputExpression = "> ";
static void inputExpression()
{
const string g_inputExpression = "> ";

void inputExpression() {
cout << g_inputExpression;
}


// TODO: refactor
static string getLine()
string getLine()
{
while(true) {
Character c = readChar();
while (true)
{
Character c = readChar();
if (char *letter = get_if<char>(&c))
{
handleChar(*letter);
Expand All @@ -41,52 +44,78 @@ static string getLine()
{
SpecialKey key = get<SpecialKey>(c);
handleSpecialKey(key);
if (key == SpecialKey::EndLine) {
if (key == SpecialKey::EndLine)
{
return getExpression();
}
}
}
}

// TODO: add arg: calculate and exit
// TODO: add output settings
// TODO: add char output
inline void calculate(OHBCalc &calculator, OutputRepresentation &representation, const string &expression, size_t offset = 0)
{
try {
auto result = calculator.eval(expression);
representation.printResult(result);
}
catch (const OHBException &expr)
{
markError(expr.getPos() + offset);
cout << expr.what() << endl;
}
catch (const exception &expr)
{
cout << "Unexpected error: " << expr.what() << endl;
}

}

} // namespace


int main(int argc, const char * argv[])
{
InitConsole consoleInitializer;

OHBCalc calculator;
OutputRepresentation representation;
string expression;

bool shouldExit = false;
for (int i = 1; i < argc; ++i)
{
expression = argv[i];
if (representation.parseOutputSettings(expression))
{
continue;
}
cout << expression << endl;
calculate(calculator, representation, expression, 0);
shouldExit = true;
}

if (shouldExit)
{
return 0;
}

InitConsole consoleInitializer;
while (true) {
inputExpression();
expression = getLine();
if (isExitSequence(expression))
{
break;
}

if (expression.empty())
if (representation.parseOutputSettings(expression))
{
continue;
}

try {
auto result = calculator.eval(expression);
cout << "d: " << result << endl;
cout << "h: " << toHex(result) << endl;
cout << "o: " << toOctal(result) << endl;
cout << "i: " << toBinary(result) << endl;
}
catch (const OHBException &expr)
{
markError(expr.getPos() + g_inputExpression.size());
cout << expr.what() << endl;
}
catch (const exception &expr)
if (expression.empty())
{
cout << expr.what() << endl;
continue;
}

calculate(calculator, representation, expression, g_inputExpression.size());
}

return 0;
Expand Down
8 changes: 6 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Arithmetic integer calculator

## Octal Hex Decimal CALCulator

Project was inspired by [sencalc](http://www.softpedia.com/get/Science-CAD/SenCalc.shtml). This calculator is intended to be cross-platform with some extra features, compared to its predecessor.

Calculator supports evaluating of expressions, mixing decimal, octal, hexadecimal, character and binary numbers like:
Expand All @@ -14,9 +16,11 @@ Base numbers are set according to preffixes or suffixes, listed in the following
|Octal | 0 | o |
|Hex | 0x | h |

Also support character (ASCII) input. It should be enclosed with double quotes. Ascii supports specials symbols, like: *\r \n \t*. For representing '\\' and '"' characters, use '\\\\' and '\\"' accordingly.
ASCII (char) input should be enclosed with double quotes. Ascii supports specials symbols, like: *\r \n \t*. For representing '\\' and '"' characters, use '\\\\' and '\\"' accordingly.

Decimal numbers are used by default and don't have any distinguishing features, like suffix or prefix. Calculator is case-insensetive, hence both 10h and 10H mean the same number.

Decimal numbers are used by default and don't have any distinguishing features. Calculator is case-insensetive, hence both 10h and 10H mean the same number. Result is shown in several bases.
Project consists of library (ohbcalc), console application (cohbcalc) and gui application (gohbcalc)

## Projects
### ohbcalc
Expand Down

0 comments on commit cc6487c

Please sign in to comment.