Add output for rss items
This commit is contained in:
parent
f028458841
commit
95e822bbc6
@ -10,4 +10,4 @@
|
|||||||
* Set to 1 to compile and run the test suite
|
* Set to 1 to compile and run the test suite
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _TESTS_ 1
|
#define _TESTS_ 0
|
||||||
|
@ -32,11 +32,16 @@ int main(int argc, char** argv) {
|
|||||||
if(!feed.isOk())
|
if(!feed.isOk())
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
|
||||||
//display requested attributes
|
|
||||||
|
//display requested attributes and items
|
||||||
std::string output = rss_utils::rss_to_list(feed, opts);
|
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;
|
delete opts;
|
||||||
return 0;
|
return 0;
|
||||||
|
127
src/options.cpp
127
src/options.cpp
@ -7,29 +7,49 @@
|
|||||||
#include "options.hpp"
|
#include "options.hpp"
|
||||||
|
|
||||||
void help(char* progName){
|
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 << "Options:\n";
|
||||||
std::cout << "Required 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 << "Channel information:\n";
|
||||||
std::cout << " [-t, --title] Get title of channel\n";
|
std::cout << " [-t, --title] Get title of channel\n";
|
||||||
std::cout << " [-l, --link] Get link to 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 << " [-e, --language] Get language code of channel\n";
|
||||||
std::cout << " [-m, --webmaster] Get webMaster's email\n";
|
std::cout << " [-m, --webmaster] Get webMaster's email\n";
|
||||||
std::cout << " [-c, --copyright] Get copyright\n";
|
std::cout << " [-c, --copyright] Get copyright\n";
|
||||||
std::cout << " [-p, --pubdate] Get publishing date\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 << " [-g, --generator] Get generator of this feed\n";
|
||||||
std::cout << " [-o, --docs] Get link to RSS documentation\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 << " [-w, --ttl] Get ttl, time that channel can be\n";
|
||||||
std::cout << " cached before being updated\n";
|
std::cout << " cached before being updated\n";
|
||||||
std::cout << " [-b, --builddate] Get last time the channel's\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 << "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);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -37,8 +57,13 @@ void help(char* progName){
|
|||||||
option_flags* parse_options(int argc, char** argv) {
|
option_flags* parse_options(int argc, char** argv) {
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
item_flags* current_item = nullptr;
|
||||||
option_flags* ret = new option_flags;
|
option_flags* ret = new option_flags;
|
||||||
|
|
||||||
|
ret->item_count = 0;
|
||||||
|
ret->items = nullptr;
|
||||||
|
|
||||||
while(true){
|
while(true){
|
||||||
c = getopt_long(argc, argv, optarg_string,
|
c = getopt_long(argc, argv, optarg_string,
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
@ -50,13 +75,22 @@ option_flags* parse_options(int argc, char** argv) {
|
|||||||
ret->uri = std::string(optarg);
|
ret->uri = std::string(optarg);
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
|
if(current_item == nullptr)
|
||||||
ret->title ^= 1;
|
ret->title ^= 1;
|
||||||
|
else
|
||||||
|
current_item->title ^= 1;
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
|
if(current_item == nullptr)
|
||||||
ret->link ^= 1;
|
ret->link ^= 1;
|
||||||
|
else
|
||||||
|
current_item->link ^= 1;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
|
if(current_item == nullptr)
|
||||||
ret->description ^= 1;
|
ret->description ^= 1;
|
||||||
|
else
|
||||||
|
current_item->description ^= 1;
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
ret->language ^= 1;
|
ret->language ^= 1;
|
||||||
@ -68,7 +102,10 @@ option_flags* parse_options(int argc, char** argv) {
|
|||||||
ret->copyright ^= 1;
|
ret->copyright ^= 1;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
|
if(current_item == nullptr)
|
||||||
ret->pubdate ^= 1;
|
ret->pubdate ^= 1;
|
||||||
|
else
|
||||||
|
current_item->pubdate ^= 1;
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
ret->managingeditor ^= 1;
|
ret->managingeditor ^= 1;
|
||||||
@ -85,7 +122,85 @@ option_flags* parse_options(int argc, char** argv) {
|
|||||||
case 'b':
|
case 'b':
|
||||||
ret->builddate ^= 1;
|
ret->builddate ^= 1;
|
||||||
break;
|
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 '?':
|
case '?':
|
||||||
|
std::cerr << "Unknown option: " << (char)optopt << std::endl;
|
||||||
case 'h':
|
case 'h':
|
||||||
help(argv[0]);
|
help(argv[0]);
|
||||||
break;
|
break;
|
||||||
|
@ -11,11 +11,12 @@
|
|||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
//cli options
|
//cli options
|
||||||
constexpr char optarg_string[] = "u:tldemcpqgowbh";
|
constexpr char optarg_string[] = ":u:tldemcpqgowbi::azfjsh";
|
||||||
|
|
||||||
static struct option long_options[] =
|
static struct option long_options[] =
|
||||||
{
|
{
|
||||||
{"uri", required_argument, 0, 'u'},
|
{"uri", required_argument, 0, 'u'},
|
||||||
|
|
||||||
{"title", no_argument, 0, 't'},
|
{"title", no_argument, 0, 't'},
|
||||||
{"link", no_argument, 0, 'l'},
|
{"link", no_argument, 0, 'l'},
|
||||||
{"description", no_argument, 0, 'd'},
|
{"description", no_argument, 0, 'd'},
|
||||||
@ -28,10 +29,32 @@ static struct option long_options[] =
|
|||||||
{"docs", no_argument, 0, 'o'},
|
{"docs", no_argument, 0, 'o'},
|
||||||
{"ttl", no_argument, 0, 'w'},
|
{"ttl", no_argument, 0, 'w'},
|
||||||
{"builddate", no_argument, 0, 'b'},
|
{"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'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{0, 0, 0, 0},
|
{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 {
|
struct option_flags {
|
||||||
unsigned int title : 1;
|
unsigned int title : 1;
|
||||||
unsigned int link : 1;
|
unsigned int link : 1;
|
||||||
@ -46,8 +69,11 @@ struct option_flags {
|
|||||||
unsigned int ttl : 1;
|
unsigned int ttl : 1;
|
||||||
unsigned int builddate : 1;
|
unsigned int builddate : 1;
|
||||||
|
|
||||||
|
item_flags* items;
|
||||||
|
unsigned int item_count;
|
||||||
std::string uri;
|
std::string uri;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void help(char*);
|
void help(char*);
|
||||||
option_flags* parse_options(int, char**);
|
option_flags* parse_options(int, char**);
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include "tylers_utils.hpp"
|
|
||||||
|
|
||||||
#include <rapidxml/rapidxml.hpp>
|
#include <rapidxml/rapidxml.hpp>
|
||||||
#include <rapidxml/rapidxml_print.hpp>
|
#include <rapidxml/rapidxml_print.hpp>
|
||||||
|
@ -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 rss_utils::rss_to_list(const rss& rss_obj, const option_flags* flags){
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
if(flags->title){
|
if(flags->title)
|
||||||
ret += rss_obj.getTitle() + "\n";
|
ret += rss_obj.getTitle() + "\n";
|
||||||
}
|
if(flags->link)
|
||||||
if(flags->link){
|
|
||||||
ret += rss_obj.getLink() + "\n";
|
ret += rss_obj.getLink() + "\n";
|
||||||
}
|
if(flags->description)
|
||||||
if(flags->description){
|
|
||||||
ret += rss_obj.getDescription() + "\n";
|
ret += rss_obj.getDescription() + "\n";
|
||||||
}
|
if(flags->language)
|
||||||
if(flags->language){
|
|
||||||
ret += rss_obj.getLanguage() + "\n";
|
ret += rss_obj.getLanguage() + "\n";
|
||||||
}
|
if(flags->webmaster)
|
||||||
if(flags->webmaster){
|
|
||||||
ret += rss_obj.getWebMaster() + "\n";
|
ret += rss_obj.getWebMaster() + "\n";
|
||||||
}
|
if(flags->copyright)
|
||||||
if(flags->copyright){
|
|
||||||
ret += rss_obj.getCopyright() + "\n";
|
ret += rss_obj.getCopyright() + "\n";
|
||||||
}
|
if(flags->pubdate)
|
||||||
if(flags->pubdate){
|
|
||||||
ret += rss_obj.getPubDate() + "\n";
|
ret += rss_obj.getPubDate() + "\n";
|
||||||
}
|
if(flags->managingeditor)
|
||||||
if(flags->managingeditor){
|
|
||||||
ret += rss_obj.getManagingEditor() + "\n";
|
ret += rss_obj.getManagingEditor() + "\n";
|
||||||
}
|
if(flags->generator)
|
||||||
if(flags->generator){
|
|
||||||
ret += rss_obj.getGenerator() + "\n";
|
ret += rss_obj.getGenerator() + "\n";
|
||||||
}
|
if(flags->docs)
|
||||||
if(flags->docs){
|
|
||||||
ret += rss_obj.getDocs() + "\n";
|
ret += rss_obj.getDocs() + "\n";
|
||||||
}
|
if(flags->ttl)
|
||||||
if(flags->ttl){
|
|
||||||
ret += rss_obj.getTTL() + "\n";
|
ret += rss_obj.getTTL() + "\n";
|
||||||
}
|
if(flags->builddate)
|
||||||
if(flags->builddate){
|
|
||||||
ret += rss_obj.getLastBuildDate() + "\n";
|
ret += rss_obj.getLastBuildDate() + "\n";
|
||||||
}
|
|
||||||
|
|
||||||
if(ret.length() > 0)
|
if(ret.length() > 0)
|
||||||
ret.pop_back();
|
ret.pop_back();
|
||||||
@ -55,3 +43,42 @@ std::string rss_utils::rss_to_list(const rss& rss_obj, const option_flags* flags
|
|||||||
|
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
@ -13,6 +13,6 @@
|
|||||||
|
|
||||||
namespace rss_utils {
|
namespace rss_utils {
|
||||||
std::string rss_to_list(const rss&, const option_flags*);
|
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*);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user