Skip to content

Instantly share code, notes, and snippets.

@LaBlazer
Last active September 2, 2019 15:42
Show Gist options
  • Save LaBlazer/a3b20c7c98f66b4de413ece0bfa7b83d to your computer and use it in GitHub Desktop.
Save LaBlazer/a3b20c7c98f66b4de413ece0bfa7b83d to your computer and use it in GitHub Desktop.
Easter calculator with HTML export (ProgTest HW3)
#ifndef __PROGTEST__
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <cstddef>
#include <cassert>
#define EASTER_OK 0
#define EASTER_INVALID_FILENAME 1
#define EASTER_INVALID_YEARS 2
#define EASTER_IO_ERROR 3
#endif
struct Date {
unsigned short Day;
unsigned short Month;
unsigned int Year;
Date(unsigned short day, unsigned short month, unsigned int year) : Day(day), Month(month), Year(year) {};
};
const char *html_head = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
"<html>\n<head>\n"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n"
"<title>C++</title>\n</head>\n<body>\n<table width=\"300\">\n"
"<tr><th width=\"99\">den</th><th width=\"99\">mesic</th><th width=\"99\">rok</th></tr>\n";
const char *html_tail = "</table>\n</body>\n</html>";
bool export_html(std::vector<Date> &dates, const char * outFileName) {
std::ofstream ofs(outFileName);
if (!ofs.good())
return false;
ofs << html_head;
for (auto d : dates)
ofs << "<tr><td>" << d.Day << "</td><td>" << (d.Month == 3 ? "brezen" : "duben") << "</td><td>" << d.Year << "</td></tr>" << std::endl;
ofs << html_tail;
return true;
}
Date get_easter_date(unsigned int year) {
int a = year % 19;
int b = year / 100;
int c = year % 100;
int d = b / 4;
int e = b % 4;
int f = (b + 8) / 25;
int g = (b - f + 1) / 3;
int h = (19 * a + b - d - g + 15) % 30;
int i = c / 4;
int k = c % 4;
int L = (32 + 2 * e + 2 * i - h - k) % 7;
int m = (a + 11 * h + 22 * L) / 451;
int month = (h + L - 7 * m + 114) / 31;
int day = ((h + L - 7 * m + 114) % 31) + 1;
return Date(day, month, year);
}
bool try_stoi(const std::string &str, int &out) {
std::string::size_type end;
try {
out = std::stoi(str, &end);
if (end == str.size())
return true;
else
return false;
}
catch (...) {
return false;
}
return true;
}
bool process_years(const std::string &str, std::vector<Date> &dates) {
std::size_t pos = str.find('-');
if (pos != std::string::npos) {
int start, end;
if (!try_stoi(str.substr(0, pos), start))
return false;
if (!try_stoi(str.substr(pos + 1, str.size()), end))
return false;
if (start > end || start <= 1582 || start >= 2200 || end <= 1582 || end >= 2200)
return false;
for (int y = start; y <= end; y++)
dates.push_back(get_easter_date(y));
}
else {
int year;
if (!try_stoi(str, year) || year <= 1582 || year >= 2200)
return false;
dates.push_back(get_easter_date(year));
}
return true;
}
int easterReport(const char * years, const char * outFileName)
{
std::string yrs(years);
std::string filename(outFileName);
for (auto & c : filename) c = toupper(c); //convert to uppercase
if (filename.size() <= 5 ||
filename.compare(filename.size() - 5, 5, ".HTML") != 0 ||
filename.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.\\/") != std::string::npos)
return EASTER_INVALID_FILENAME;
for (std::size_t i = 0; i < yrs.length(); i++) //remove the whitespaces
if (yrs[i] == ' ') {
yrs.erase(i, 1);
i--;
}
if (yrs.size() < 4 || yrs.find_first_not_of("0123456789-,") != std::string::npos)
return EASTER_INVALID_YEARS;
std::vector<Date> dates;
std::size_t start = 0;
std::size_t end = yrs.find(',');
while (end != std::string::npos)
{
if (!process_years(yrs.substr(start, end - start), dates))
return EASTER_INVALID_YEARS;
start = end + 1;
end = yrs.find(',', start);
}
//process the last year
if (!process_years(yrs.substr(start, yrs.size()), dates))
return EASTER_INVALID_YEARS;
if (!export_html(dates, outFileName))
return EASTER_IO_ERROR;
return EASTER_OK;
}
#ifndef __PROGTEST__
int main(int argc, char * argv[])
{
assert(easterReport("2012,2013,2015-2020,2020-2222", "out0.html") == EASTER_INVALID_YEARS);
assert(easterReport("2000 - 2014", "out1.html") == EASTER_OK);
assert(easterReport("2001 , 2002 , 2003 ,2005,2006", "out2.html") == EASTER_OK);
assert(easterReport("2000,2011,2010-2020", "out3.html") == EASTER_OK);
assert(easterReport("2000-3000", "out4.html") == EASTER_INVALID_YEARS);
assert(easterReport("1002, 1554, 1984-1998, 1222", "out5.html") == EASTER_INVALID_YEARS);
assert(easterReport(" 1300", "out6.htm") == EASTER_INVALID_FILENAME);
assert(easterReport(" 1300", "out7.html") == EASTER_INVALID_YEARS);
assert(easterReport("1200-1300", "out8.html") == EASTER_INVALID_YEARS);
assert(easterReport(",1600", "out9.html") == EASTER_INVALID_YEARS);
assert(easterReport("1600,", "out10.html") == EASTER_INVALID_YEARS);
std::cout << "Tests succeeded!" << std::endl;
return 0;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment