-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFractalDrawer.cpp
168 lines (155 loc) · 4.17 KB
/
FractalDrawer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// ------------------------------ includes ------------------------------
#include <boost/tokenizer.hpp>
#include <boost/filesystem.hpp>
#include <string>
#include <iostream>
#include "Fractal.h"
// -------------------------- const definitions -------------------------
/**
* The massage to be printed if the number of argument sent wasn't good
*/
#define ERR_USAGE "Usage: FractalDrawer <file path>"
/**
* The massage to be printed if there was a problem with the input (invalid or non-existing file)
*/
#define ERR_INPUT "Invalid input"
/**
* The number of arguments that the program should get
*/
#define ARGS_COUNT 2
/**
* @brief this is the only file type that is considered valid
*/
#define NEEDED_FILE_TYPE ".csv"
// ------------------------------ functions -----------------------------
/**
* @brief this outputs to cerr an invalid input error message, and exits with exit code of failure
*/
void inputErr()
{
std::cerr << ERR_INPUT << std::endl;
exit(EXIT_FAILURE);
}
/**
* @brief this holds the wanted fractal's values- the type and dimensions of it
*/
struct NeededFractal
{
int type;
int dimension;
} typedef NeededFractal;
/**
* @brief this checks if the file given is valid- that is exists and is in the wanted type
* @param path
*/
void checkFileValid(const boost::filesystem::path &path)
{
if (!boost::filesystem::exists(path))
{
inputErr();
}
if (path.extension() != NEEDED_FILE_TYPE)
{
inputErr();
}
}
/**
* reads file into vector with checking if holds the right value type and is in bounds
* @param path the path to a file to read
* @param v the vector to read the information to
*/
void readFileToVector(const boost::filesystem::path &path, std::vector<NeededFractal> &v)
{
typedef boost::tokenizer <boost::char_separator<char>> tokenizer;
boost::filesystem::ifstream toRead(path);
std::string line;
boost::char_separator<char> sep(",", " ", boost::keep_empty_tokens);
while (std::getline(toRead, line))
{
if (line.empty())
{
inputErr();
}
tokenizer tok{line, sep};
int type = 0;
int dim = 0;
int numTokens = 0;
for (const auto &t: tok)
{
if (t.length() != 1 || t == " ")
{
inputErr();
}
if (!std::isdigit(t.c_str()[0]))
{ // I know it has the length of 1
inputErr();
}
int n = std::stoi(t);
if (numTokens == 0)
{
if (n > MAX_INDEX || n < MIN_INDEX)
{
inputErr();
}
type = n;
numTokens += 1;
}
else
{
if (numTokens != 1 || n > MAX_DIM || n < MIN_DIM)
{
inputErr();
}
dim = n;
numTokens += 1;
}
}
if (numTokens != 2)
{
inputErr();
}
v.push_back({type, dim});
}
}
/**
* @brief this sends the fractal's information one by one in reversed order to the fractal
* factory which makes them, and then this function prints them
* @param v the vector that holds the information about the needed fractals
*/
void printFractals(std::vector<NeededFractal> v)
{
for (auto it = v.rbegin(); it != v.rend(); ++it)
{
Fractal *f;
f = FractalFactory::makeFractal(it->type, it->dimension);
f->makeAndPrint();
delete (f);
}
}
/**
* @brief this reads, validates and prints the fractals as needed
* @param path the path to the file to read the information from
*/
void dealWithInput(const boost::filesystem::path &path)
{
checkFileValid(path);
std::vector<NeededFractal> v;
readFileToVector(path, v);
printFractals(v);
}
/**
* Program's main
* @param argc count of args
* @param argv args values
* @return program exit status code
*/
int main(int argc, char **argv)
{
if (argc != ARGS_COUNT)
{
std::cerr << ERR_USAGE << std::endl;
exit(EXIT_FAILURE);
}
dealWithInput(boost::filesystem::path{argv[1]});
return EXIT_SUCCESS;
}