Add output for rss items

This commit is contained in:
Clortox 2021-07-25 17:05:40 -04:00
parent f028458841
commit 95e822bbc6
7 changed files with 212 additions and 40 deletions

View File

@ -10,4 +10,4 @@
* Set to 1 to compile and run the test suite
*/
#define _TESTS_ 1
#define _TESTS_ 0

View File

@ -32,11 +32,16 @@ int main(int argc, char** argv) {
if(!feed.isOk())
exit(-1);
//display requested attributes
//display requested attributes and items
std::string output = rss_utils::rss_to_list(feed, opts);
std::cout << output << std::endl;
if(opts->items != nullptr){
feed.getItems();
output += "\n" + rss_utils::rss_to_items(feed, opts);
}
std::cout << output << std::endl;
delete opts;
return 0;

View File

@ -7,29 +7,49 @@
#include "options.hpp"
void help(char* progName){
std::cout << "Usage: " << progName << " [-u FEED_URI]\n";
std::cout << "Usage: " << progName << " [-u FEED_URI] [CHANNEL FLAGS] ";
std::cout << "[-i ITEM_INDEX] [ITEM FLAGS]\n";
std::cout << "Options:\n";
std::cout << "Required Options:\n";
std::cout << " [-u, --uri] URI of the rss stream\n\n";
std::cout << " [-u, --uri] URI URI of the rss stream\n\n";
std::cout << "Channel information:\n";
std::cout << " [-t, --title] Get title of channel\n";
std::cout << " [-l, --link] Get link to channel\n";
std::cout << " [-d, --description] Get Description of channel\n";
std::cout << " [-d, --description] Get description of channel\n";
std::cout << " [-e, --language] Get language code of channel\n";
std::cout << " [-m, --webmaster] Get webMaster's email\n";
std::cout << " [-c, --copyright] Get copyright\n";
std::cout << " [-p, --pubdate] Get publishing date\n";
std::cout << " [-q, --managingeditor] Get Managing Editor\n";
std::cout << " [-q, --managingeditor] Get managing editor\n";
std::cout << " [-g, --generator] Get generator of this feed\n";
std::cout << " [-o, --docs] Get link to RSS documentation\n";
std::cout << " [-w, --ttl] Get ttl, time that channel can be\n";
std::cout << " cached before being updated\n";
std::cout << " [-b, --builddate] Get last time the channel's\n";
std::cout << " content changed\n\n";
std::cout << " content changed\n";
std::cout << " [-i, --item] INDEX Provide index of item to display\n";
std::cout << " If no index is provided, assume the first\n";
std::cout << " item in the feed. All following flags will\n";
std::cout << " be parsed as item options, till another\n";
std::cout << " item is provided\n\n";
std::cout << "Item options:\n";
std::cout << " [-t, --title] Get title of item\n";
std::cout << " [-l, --link] Get link\n";
std::cout << " [-d, --description] Get description\n";
std::cout << " [-a, --author] Get author\n";
std::cout << " [-z, --category] Get category list\n";
std::cout << " [-f, --comments] Get link to comments\n";
std::cout << " [-j, --guid] Get GUID\n";
std::cout << " [-p, --pubdate] Get publishing date\n";
std::cout << " [-s, --source] Get source of item\n\n";
std::cout << "General options:\n";
std::cout << " [-h, --help] Show this message\n";
std::cout << " [-h, --help] Show this message\n\n";
std::cout << "For more information, refer to the RSS 2.0 documentation\n";
std::cout << "https://validator.w3.org/feed/docs/rss2.html\n";
exit(1);
}
@ -37,8 +57,13 @@ void help(char* progName){
option_flags* parse_options(int argc, char** argv) {
int option_index = 0;
int c;
item_flags* current_item = nullptr;
option_flags* ret = new option_flags;
ret->item_count = 0;
ret->items = nullptr;
while(true){
c = getopt_long(argc, argv, optarg_string,
long_options, &option_index);
@ -50,13 +75,22 @@ option_flags* parse_options(int argc, char** argv) {
ret->uri = std::string(optarg);
break;
case 't':
ret->title ^= 1;
if(current_item == nullptr)
ret->title ^= 1;
else
current_item->title ^= 1;
break;
case 'l':
ret->link ^= 1;
if(current_item == nullptr)
ret->link ^= 1;
else
current_item->link ^= 1;
break;
case 'd':
ret->description ^= 1;
if(current_item == nullptr)
ret->description ^= 1;
else
current_item->description ^= 1;
break;
case 'e':
ret->language ^= 1;
@ -68,7 +102,10 @@ option_flags* parse_options(int argc, char** argv) {
ret->copyright ^= 1;
break;
case 'p':
ret->pubdate ^= 1;
if(current_item == nullptr)
ret->pubdate ^= 1;
else
current_item->pubdate ^= 1;
break;
case 'q':
ret->managingeditor ^= 1;
@ -85,7 +122,85 @@ option_flags* parse_options(int argc, char** argv) {
case 'b':
ret->builddate ^= 1;
break;
case 'i':
if(ret->items == nullptr){
ret->items = new item_flags[ret->item_count + 1];
current_item = &(ret->items[0]);
ret->item_count++;
current_item->index = optarg ? atoi(optarg) : 0;
} else {
item_flags* new_flags = new item_flags[ret->item_count + 1];
for(unsigned int i=0;i<ret->item_count;++i)
new_flags[i] = ret->items[i];
delete ret->items;
ret->items = new_flags;
current_item = &(ret->items[ret->item_count]);
ret->item_count++;
current_item->index = optarg ? atoi(optarg) : 0;
}
break;
case 'a':
if(current_item == nullptr){
std::cerr << "Invalid option in this context: [-a --author]" << std::endl;
std::cerr << "Did you provide the [-i --index] flag first?" << std::endl;
} else
current_item->author ^= 1;
break;
case 'z':
if(current_item == nullptr){
std::cerr << "Invalid option in this context: [-z --category]" << std::endl;
std::cerr << "Did you provide the [-i --index] flag first?" << std::endl;
} else
current_item->category ^= 1;
break;
case 'f':
if(current_item == nullptr){
std::cerr << "Invalid option in this context: [-f --comments]" << std::endl;
std::cerr << "Did you provide the [-i --index] flag first?" << std::endl;
} else
current_item->comments ^= 1;
break;
case 'j':
if(current_item == nullptr){
std::cerr << "Invalid option in this context: [-j --guid]" << std::endl;
std::cerr << "Did you provide the [-i --index] flag first?" << std::endl;
} else
current_item->guid ^= 1;
break;
case 's':
if(current_item == nullptr){
std::cerr << "Invalid option in this context: [-s --source]" << std::endl;
std::cerr << "Did you provide the [-i --index] flag first?" << std::endl;
} else
current_item->source ^= 1;
break;
case ':': //go here if flag that requires argument is passed, but no arg given
switch(optopt){
case 'i':
if(ret->items == nullptr){
ret->item_count++;
ret->items = new item_flags[ret->item_count];
current_item = &(ret->items[0]);
current_item->index = 1;
} else {
item_flags* new_flags = new item_flags[ret->item_count + 1];
for(unsigned int i=0;i<ret->item_count;++i)
new_flags[i] = ret->items[i];
delete ret->items;
ret->items = new_flags;
current_item = &(ret->items[ret->item_count]);
ret->item_count++;
current_item->index = 1;
}
break;
default:
std::cerr << "Invalid use: option -" << (char)optopt
<< " requires an argument" << std::endl;
break;
}
break;
case '?':
std::cerr << "Unknown option: " << (char)optopt << std::endl;
case 'h':
help(argv[0]);
break;

View File

@ -11,11 +11,12 @@
#include <getopt.h>
//cli options
constexpr char optarg_string[] = "u:tldemcpqgowbh";
constexpr char optarg_string[] = ":u:tldemcpqgowbi::azfjsh";
static struct option long_options[] =
{
{"uri", required_argument, 0, 'u'},
{"title", no_argument, 0, 't'},
{"link", no_argument, 0, 'l'},
{"description", no_argument, 0, 'd'},
@ -28,10 +29,32 @@ static struct option long_options[] =
{"docs", no_argument, 0, 'o'},
{"ttl", no_argument, 0, 'w'},
{"builddate", no_argument, 0, 'b'},
{"item", optional_argument, 0, 'i'},
{"author", no_argument, 0, 'a'},
{"category", no_argument, 0, 'z'},
{"comments", no_argument, 0, 'f'},
{"guid", no_argument, 0, 'j'},
{"source", no_argument, 0, 's'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0},
};
struct item_flags {
unsigned int title : 1;
unsigned int link : 1;
unsigned int description : 1;
unsigned int author : 1;
unsigned int category : 1;
unsigned int comments : 1;
unsigned int guid : 1;
unsigned int pubdate : 1;
unsigned int source : 1;
int index;
};
struct option_flags {
unsigned int title : 1;
unsigned int link : 1;
@ -46,8 +69,11 @@ struct option_flags {
unsigned int ttl : 1;
unsigned int builddate : 1;
item_flags* items;
unsigned int item_count;
std::string uri;
};
void help(char*);
option_flags* parse_options(int, char**);

View File

@ -15,7 +15,6 @@
#include <map>
#include <iostream>
#include <stdexcept>
#include "tylers_utils.hpp"
#include <rapidxml/rapidxml.hpp>
#include <rapidxml/rapidxml_print.hpp>

View File

@ -11,42 +11,30 @@ using namespace rss_utils;
std::string rss_utils::rss_to_list(const rss& rss_obj, const option_flags* flags){
std::string ret;
if(flags->title){
if(flags->title)
ret += rss_obj.getTitle() + "\n";
}
if(flags->link){
if(flags->link)
ret += rss_obj.getLink() + "\n";
}
if(flags->description){
if(flags->description)
ret += rss_obj.getDescription() + "\n";
}
if(flags->language){
if(flags->language)
ret += rss_obj.getLanguage() + "\n";
}
if(flags->webmaster){
if(flags->webmaster)
ret += rss_obj.getWebMaster() + "\n";
}
if(flags->copyright){
if(flags->copyright)
ret += rss_obj.getCopyright() + "\n";
}
if(flags->pubdate){
if(flags->pubdate)
ret += rss_obj.getPubDate() + "\n";
}
if(flags->managingeditor){
if(flags->managingeditor)
ret += rss_obj.getManagingEditor() + "\n";
}
if(flags->generator){
if(flags->generator)
ret += rss_obj.getGenerator() + "\n";
}
if(flags->docs){
if(flags->docs)
ret += rss_obj.getDocs() + "\n";
}
if(flags->ttl){
if(flags->ttl)
ret += rss_obj.getTTL() + "\n";
}
if(flags->builddate){
if(flags->builddate)
ret += rss_obj.getLastBuildDate() + "\n";
}
if(ret.length() > 0)
ret.pop_back();
@ -55,3 +43,42 @@ std::string rss_utils::rss_to_list(const rss& rss_obj, const option_flags* flags
return ret;
}
std::string rss_utils::rss_to_items(const rss& rss_obj, const option_flags* flags){
item_flags* items = flags->items;
int maxItem = rss_obj.getItemCount();
std::string ret;
for(unsigned int i=0; i < flags->item_count; ++i, ++items){
//if has a valid index
if(items->index >= 0 && items->index < maxItem){
rss_utils::item cur_item = rss_obj[items->index];
if(items->title)
ret += cur_item.getTitle() + "\n";
if(items->link)
ret += cur_item.getLink() + "\n";
if(items->description)
ret += cur_item.getDescription() + "\n";
if(items->author)
ret += cur_item.getAuthor() + "\n";
if(items->category)
ret += cur_item.getCategory() + "\n";
if(items->comments)
ret += cur_item.getComments() + "\n";
if(items->guid)
ret += cur_item.getGuid() + "\n";
if(items->pubdate)
ret += cur_item.getPubDate() + "\n";
if(items->source)
ret += cur_item.getSource() + "\n";
} else
std::cerr << "Index on item " << i << " is not valid!" << std::endl;
}
if(ret.length() > 0)
ret.pop_back();
else
ret = "<No arguments given for items>";
return ret;
}

View File

@ -13,6 +13,6 @@
namespace rss_utils {
std::string rss_to_list(const rss&, const option_flags*);
//std::string rss_to_items(const rss&
std::string rss_to_items(const rss&, const option_flags*);
}