Browse Source

Improved design patter and added Doxyfile.

stable
Maximilian Stiefel 6 years ago
parent
commit
fd101faa6a
  1. 36
      README.md
  2. 11
      compile_and_install_ubuntu.sh
  3. 7
      dict.h
  4. 36
      dict/creator.h
  5. 14
      dict/deen.cc
  6. 24
      dict/deen.h
  7. 14
      dict/desv.cc
  8. 13
      dict/desv.h
  9. 115
      dict/dict_imp.cc
  10. 70
      dict/dict_int.h
  11. 0
      dict/exceptions.h
  12. 17
      dict/types.h
  13. 103
      dictcc.cc
  14. 179
      dictcc/dict.h
  15. 2494
      doc/Doxyfile

36
README.md

@ -0,0 +1,36 @@
Unoffical C++ API for dict.cc
## Prequisites
curl and curlpp have to be installed on the system.
## Installation
So far only a quick and dirty solution is available:
bash compile_and_install_ubuntu.sh
Works definitely under Ubuntu, other OS unsure and untested. CMake file will follow.
## Usage of the CLI
Type
dictcc -h
## Usage of the Library
An example of how the library is supposed to be used is given with the CLI (*dictcc.cc*). The following
code creates a dictionary and performs a search.
```c++
#include "dict.h"
...
dictionary = dictcc::creator::create(lang);
result = dictionary->search(search_chr);
```
`dictcc::creator::create` takes a string e.g. DESV and returns a
`std::smart_ptr` to a dictionary object. The return value of the search
function is a smart pointer to a `std::pair` of two string vectors, each
corresponding to one language.

11
compile_and_install_ubuntu.sh

@ -0,0 +1,11 @@
#!/bin/sh
COMPILE_CMD="g++ dict/*.cc dictcc.cc -o dictcc -lcurl -lcurlpp -g"
INST_FILE="/usr/local/bin/dictcc"
INST_CMD="sudo ln -s $PWD/dictcc $INST_FILE"
echo "Compiling ... "
$COMPILE_CMD
echo "Installing ..."
if [ ! -f "$INST_FILE" ]
then
$INST_CMD
fi

7
dict.h

@ -0,0 +1,7 @@
#ifndef DICTCC_DICT_INCLUDED
#define DICTCC_DICT_INCLUDED
#include "dict/dict_int.h"
#include "dict/creator.h"
#endif // DICTCC_DICT_INCLUDED

36
dict/creator.h

@ -0,0 +1,36 @@
#ifndef DICTCC_CREATOR_INCLUDED
#define DICTCC_CREATOR_INCLUDED
// Dictcc API
#include "dict_int.h"
#include "desv.h"
#include "deen.h"
#include "types.h"
#include "exceptions.h"
namespace dictcc
{
class creator
{
private:
creator(){}
~creator(){}
public:
static std::shared_ptr<dict> create(const std::string langs)
{
lang_t l = dict::str2langs(langs);
// TODO: Add new languages here
switch (l) {
case DESV:
return std::make_shared<desv>();
case DEEN:
return std::make_shared<deen>();
default:
throw(dict_lang_error(__FILE__, __LINE__));
}
}
};
} // namespace dictcc
#endif // DICTCC_DESV_INCLUDED

14
dict/deen.cc

@ -0,0 +1,14 @@
#include "deen.h"
namespace dictcc
{
deen::deen()
{
d_suburl = "deen";
}
bool deen::noun(const std::ostringstream& req_answer, str_list_t& res)
{
return false;
}
} // namespace dictcc

24
dict/deen.h

@ -0,0 +1,24 @@
#ifndef DICTCC_DEEN_INCLUDED
#define DICTCC_DEEN_INCLUDED
// STD
#include <sstream>
// Boost
// Dictcc API
#include "dict_int.h"
namespace dictcc
{
class deen : public dict
{
// TODO: Implement specifics of the language here.
private:
bool noun(const std::ostringstream& req_answer, str_list_t& res);
public:
deen();
~deen()
{}
};
} // namespace dictcc
#endif // DICTCC_DEEN_INCLUDED

14
dict/desv.cc

@ -0,0 +1,14 @@
#include "desv.h"
namespace dictcc
{
desv::desv()
{
d_suburl = "desv";
}
bool desv::noun(const std::ostringstream& req_answer, str_list_t& res)
{
return false;
}
} // namespace dictcc

13
dictcc/desv.h → dict/desv.h

@ -1,25 +1,24 @@
#ifndef DICTCC_DESV_INCLUDED
#define DICTCC_DESV_INCLUDED
// STD
#include <sstream>
// Dictcc API
#include "dict.h"
#include "dict_int.h"
namespace dictcc
{
class desv : public dict
{
// TODO: Implement specifics of the language here.
private:
bool noun(const std::ostringstream& req_answer, str_list_t& res);
public:
desv();
~desv()
{}
};
desv::desv()
{
d_suburl = "desv";
}
} // namespace dictcc
#endif // DICTCC_DESV_INCLUDED

115
dict/dict_imp.cc

@ -0,0 +1,115 @@
#include "dict_int.h"
namespace dictcc
{
const std::string dict::URL_HTTPS = "https://";
const std::string dict::URL_REST = ".dict.cc/?s=";
const std::string dict::QUERYA = "c1Arr = new Array";
const std::string dict::QUERYB = "c2Arr = new Array";
const std::string dict::QUERYC = ");";
const std::string dict::SEPERATOR = "\",\"";
void dict::parse_answer(const std::ostringstream& req_answer, const std::string& query, str_list_t& res)
{
std::string page = req_answer.str();
auto lstart = page.find(query);
auto lend = page.find(QUERYC, lstart);
// No results found -> throw an exception
if(lstart == -1)
throw(dict_no_results(__FILE__, __LINE__));
lstart += query.size();
// Scroll to the first character
while( (page[lstart] == '\"') || (page[lstart] == ',') || (page[lstart] == '(') )
lstart++;
// Scroll to the last character
while( (page[lstart] == '\"') || (page[lstart] == ',') || (page[lstart] == '(') )
lend--;
// Get the line.
std::string line = page.substr(lstart, lend-lstart);
// Split it.
boost::split(res, line, boost::is_any_of(SEPERATOR), boost::token_compress_on);
// Last element is usually empty.
if ( *(res.end()-1) == "") {
res.pop_back();
}
}
search_ptr_t dict::search(std::string word)
{
std::ostringstream answer;
// Perform HTTP request with SSL below.
try {
std::string dict_req = URL_HTTPS + d_suburl + URL_REST + word;
curlpp::options::Url url(dict_req);
d_request.setOpt(url);
answer << d_request;
} catch(curlpp::RuntimeError &e) {
std::ostringstream ss;
ss << e.what() << "(curlpp::RuntimeError).";
throw(dict_libcurl_error(__FILE__, __LINE__, ss.str()));
} catch(curlpp::LogicError &e) {
std::ostringstream ss;
ss << e.what() << "(curlpp::LogicError).";
throw(dict_libcurl_error(__FILE__, __LINE__, ss.str()));
}
// Convert request into word lists language one and language two respectively.
str_list_t l0, l1;
try {
parse_answer(answer, QUERYA, l0);
parse_answer(answer, QUERYB, l1);
} catch (dict_no_results& e) {
// The parsing might go wrong.
e << std::string("Could not find ") + std::string("\"") + word + std::string("\".");
throw;
}
// Check if there are words without translation
if (l0.size() != l1.size()) {
auto min = std::min(l0.size(), l1.size());
l0.resize(min);
l1.resize(min);
}
// Make pair and return shared pointer to it.
auto pair = std::make_pair(l0, l1);
if (d_translations == nullptr) {
d_translations = std::make_shared<search_t>(pair);
} else {
*d_translations = pair;
}
// Return a shared pointer to the pair of lists
return d_translations;
}
std::string dict::langs2str(const lang_t& lt)
{
// TODO: Add new languages here.
std::vector<std::string> str = {"DESV", "DEEN"};
if (lt >= str.size()) {
throw(dict_lang_error(__FILE__, __LINE__));
}
return str[lt];
}
lang_t dict::str2langs(const std::string& str)
{
if (str == "DESV") {
return DESV;
} else if ( str == "DEEN") {
return DEEN;
} else {
throw(dict_lang_error(__FILE__, __LINE__));
}
}
size_t dict::actual_size(std::string str)
{
size_t bytes_checked = 0;
size_t actual_size = 0;
while (bytes_checked < str.size()) {
bytes_checked += std::mblen(&str.c_str()[bytes_checked], str.size() - bytes_checked);
actual_size++;
}
return actual_size;
}
} // namespace dictcc

70
dict/dict_int.h

@ -0,0 +1,70 @@
#ifndef DICTCC_DICT_INTERFACE_INCLUDED
#define DICTCC_DICT_INTERFACE_INCLUDED
// STD
#include <string>
#include <sstream>
#include <iostream>
#include <utility>
#include <functional>
#include <vector>
#include <clocale>
// Curl
#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>
// Boost
#include <boost/algorithm/string.hpp>
// Dictcc API
#include "types.h"
#include "exceptions.h"
namespace dictcc
{
/*! \brief Base dictionary class.
*/
class dict
{
private:
static const std::string URL_HTTPS;
static const std::string URL_REST;
static const std::string QUERYA;
static const std::string QUERYB;
static const std::string QUERYC;
static const std::string SEPERATOR;
private:
/*! \brief Translations found by the search for a string.
*/
search_ptr_t d_translations;
/*! \brief Additional information e.g. different forms of a verb.
*/
search_ptr_t d_additional;
curlpp::Easy d_request;
curlpp::Cleanup d_cleaner;
lang_t d_langs;
private:
void parse_answer(const std::ostringstream& req_answer, const std::string& query, str_list_t& res);
virtual bool noun(const std::ostringstream& req_answer, str_list_t& res)=0;
protected:
std::string d_suburl;
protected:
dict(){setlocale(LC_ALL, "");}
public:
virtual ~dict(){}
public:
search_ptr_t search(std::string word);
static std::string langs2str(const lang_t& lt);
static lang_t str2langs(const std::string& str);
/*! \brief Help function: Get the size of a string in chars containing multibyte characters e.g. ü.
*/
static size_t actual_size(std::string str);
};
} // namespace dictcc
#endif // DICTCC_DICT_INTERFACE_INCLUDED

0
dictcc/exceptions.h → dict/exceptions.h

17
dictcc/types.h → dict/types.h

@ -1,19 +1,24 @@
#ifndef DICTCC_TYPES_INCLUDED
#define DICTCC_TYPES_INCLUDED
// STD
#include <string>
#include <utility>
#include <functional>
#include <vector>
#ifndef DICTCC_TYPES_INCLUDED
#define DICTCC_TYPES_INCLUDED
// Dictcc API
//#include "dict.h"
namespace dictcc
{
/*! \brief List of words in one language.
*/
typedef std::vector<std::string> word_list_t;
/*! \brief Pair of two word lists with corresponding word/sentence pairs (translations) resulting from a search string.
typedef std::vector<std::string> str_list_t;
/*! \brief Pair of two string lists resulting from a search.
*/
typedef std::pair<str_list_t, str_list_t> search_t;
/*! \brief Shared pointer to search_t.
*/
typedef std::pair<word_list_t*, word_list_t*> search_t;
typedef std::shared_ptr<search_t> search_ptr_t;
/*! \brief Supported language pairs.
*/
typedef enum

103
dictcc.cc

@ -0,0 +1,103 @@
#include <iostream>
#include "dict.h"
int main(int argc, char **argv)
{
setlocale(LC_ALL, "");
int c;
char* lang_chr = nullptr;
char* search_chr = nullptr;
int nwords = -1;
// TODO: Add new languages here.
std::ostringstream langs;
langs << " DESV" << std::endl
<< " DEEN" << std::endl;
// Help stringstream
std::ostringstream help;
help << "dictcc [OPTION] [ARGUMENT]" << std::endl
<< "-h Print this help message." << std::endl
<< "-l Specify language." << std::endl
<< " Currently supported:" << std::endl
<< langs.str()
<< "-s Word to search for." << std::endl
<< "-n Number of words to be printed"<< std::endl;
// Settings getopt.
opterr = 0;
// Get arguments.
while ( (c = getopt (argc, argv, "hl:s:n:") ) != -1) {
switch (c)
{
case 'h':
std::cout << help.str();
exit(EXIT_SUCCESS);
case 'l':
lang_chr = optarg;
break;
case 's':
search_chr = optarg;
break;
case 'n':
nwords = std::stol(optarg);
break;
case '?':
if (isprint (optopt))
std::cerr << "Unknown option " << optopt << std::endl;
else
std::cerr << "Unknown option character." << std::endl;
exit(EXIT_FAILURE);
default:
abort ();
}
}
// Sanity checks.
if (argc < 2) {
std::cout << "Please use this CLI the following way.\n" << std::endl;
std::cout << help.str();
exit(EXIT_FAILURE);
}
if (lang_chr == nullptr) {
std::cerr << "Language has to specified." << std::endl;
exit(EXIT_FAILURE);
}
if (search_chr == nullptr) {
std::cerr << "String to search for has to be specified." << std::endl;
exit(EXIT_FAILURE);
}
// Make new didctionary and search.
std::string lang(lang_chr);
std::shared_ptr<dictcc::dict> dictionary = nullptr;
dictcc::search_ptr_t result;
try {
dictionary = dictcc::creator::create(lang);
result = dictionary->search(search_chr);
} catch (const dictcc::dict_exception& e) {
std::cout << "Unfortunately something went wrong. We are very sorry about that :(" << std::endl
<< "See below for further information on the error occured." << std::endl
<< e.what() << std::endl;
exit(EXIT_FAILURE);
}
// A search returns a pair of word lists.
int max_len = 0;
// Find longest strting for formatting purposes.
for (const std::string& str: result->first) {
if (dictcc::dict::actual_size(str) > max_len) {
max_len = dictcc::dict::actual_size(str);
}
}
// Default number of words to be printed is 8.
if (nwords < 0) {
nwords = (result->first).size() > 8 ? nwords = 8 : nwords = (result->first).size();
}
// Avoid segmentation fault.
if (nwords > (result->first).size()) {
nwords = (result->first).size();
}
// Print on console.
for (int i = 0; i < nwords; i++) {
std::cout << (result->first)[i];
for (int j=0; j < ( max_len - dictcc::dict::actual_size( (result->first)[i] ) + 10); j++) {
std::cout << ".";
}
std::cout << (result->second)[i] << std::endl;
}
}

179
dictcc/dict.h

@ -1,179 +0,0 @@
// STD
#include <string>
#include <sstream>
#include <iostream>
#include <utility>
#include <functional>
#include <vector>
// Curl
#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>
// Boost
#include <boost/algorithm/string.hpp>
// Dictcc API
#include "types.h"
#include "exceptions.h"
#ifndef DICTCC_DICT_INCLUDED
#define DICTCC_DICT_INCLUDED
namespace dictcc
{
/*! \brief Base dictionary class.
*/
class dict
{
protected:
static const std::string URL_HTTPS;
static const std::string URL_REST;
static const std::string QUERYA;
static const std::string QUERYB;
static const std::string QUERYC;
static const std::string SEPERATOR;
protected:
/*! \brief Word list corresponding to one language.
*/
word_list_t d_wordsl0;
/*! \brief Word list corresponding to one language.
*/
word_list_t d_wordsl1;
curlpp::Easy d_request;
curlpp::Cleanup d_cleaner;
lang_t d_langs;
std::string d_suburl;
protected:
void parse_answer(const std::ostringstream& os, const std::string& query, word_list_t& vec);
protected:
dict(){}
public:
static dict* create(const std::string langs);
virtual ~dict(){}
public:
search_t search(std::string word);
static std::string langs2str(const lang_t& lt);
static lang_t str2langs(const std::string& str);
};
const std::string dict::URL_HTTPS = "https://";
const std::string dict::URL_REST = ".dict.cc/?s=";
const std::string dict::QUERYA = "c1Arr = new Array";
const std::string dict::QUERYB = "c2Arr = new Array";
const std::string dict::QUERYC = ");";
const std::string dict::SEPERATOR = "\",\"";
void dict::parse_answer(const std::ostringstream& os, const std::string& query, word_list_t& vec)
{
std::string page = os.str();
auto lstart = page.find(query);
auto lend = page.find(QUERYC, lstart);
// No results found -> throw an exception
if(lstart == -1)
throw(dict_no_results(__FILE__, __LINE__));
lstart += query.size();
// Scroll to the first character
while( (page[lstart] == '\"') || (page[lstart] == ',') || (page[lstart] == '(') )
lstart++;
// Scroll to the last character
while( (page[lstart] == '\"') || (page[lstart] == ',') || (page[lstart] == '(') )
lend--;
// Get the line.
std::string line = page.substr(lstart, lend-lstart);
// Split it.
boost::split(vec, line, boost::is_any_of(SEPERATOR), boost::token_compress_on);
// Last element is always empty.
vec.pop_back();
// Make sure, that the string termination is present.
for (std::string& str : vec) {
if (str[str.size()-1] != '\0' ) {
str.append("\0");
}
}
}
search_t dict::search(std::string word)
{
std::ostringstream answer;
// Perform HTTP request with SSL below.
try {
std::string dict_req = URL_HTTPS + d_suburl + URL_REST + word;
curlpp::options::Url url(dict_req);
d_request.setOpt(url);
answer << d_request;
} catch(curlpp::RuntimeError &e) {
std::ostringstream ss;
ss << e.what() << "(curlpp::RuntimeError).";
throw(dict_libcurl_error(__FILE__, __LINE__, ss.str()));
} catch(curlpp::LogicError &e) {
std::ostringstream ss;
ss << e.what() << "(curlpp::LogicError).";
throw(dict_libcurl_error(__FILE__, __LINE__, ss.str()));
}
// Convert request into word lists language one and language two respectively.
try {
parse_answer(answer, QUERYA, d_wordsl0);
parse_answer(answer, QUERYB, d_wordsl1);
} catch (dict_no_results& e) {
// The parsing might go wrong.
e << std::string("Could not find ") + std::string("\"") + word + std::string("\".");
throw;
}
// Return a pair of references
return std::make_pair(&d_wordsl0, &d_wordsl1);
}
inline std::string dict::langs2str(const lang_t& lt)
{
// TODO: Add new languages here.
std::vector<std::string> str = {"DESV", "DEEN"};
if (lt >= str.size()) {
throw(dict_lang_error(__FILE__, __LINE__));
}
return str[lt];
}
inline lang_t dict::str2langs(const std::string& str)
{
if (str == "DESV") {
return DESV;
} else if ( str == "DEEN") {
return DEEN;
} else {
throw(dict_lang_error(__FILE__, __LINE__));
}
}
class desv : public dict
{
// TODO: Implement specifics of the language here.
public:
desv();
~desv()
{}
};
desv::desv()
{
d_suburl = "desv";
}
dict* dict::create(const std::string langs)
{
lang_t l = str2langs(langs);
// TODO: Add new languages here
switch (l) {
case DESV:
return new desv;
break;
default:
throw(dict_lang_error(__FILE__, __LINE__));
}
}
} // namespace dictcc
#endif // DICTCC_DICT_INCLUDED

2494
doc/Doxyfile

File diff suppressed because it is too large
Loading…
Cancel
Save