mirror of
				https://github.com/Clortox/rss-cli.git
				synced 2025-07-17 14:12:11 +00:00 
			
		
		
		
	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; | ||||||
|  | |||||||
							
								
								
									
										135
									
								
								src/options.cpp
									
									
									
									
									
								
							
							
						
						
									
										135
									
								
								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': | ||||||
|                 ret->title ^= 1; |                 if(current_item == nullptr) | ||||||
|  |                     ret->title ^= 1; | ||||||
|  |                 else | ||||||
|  |                     current_item->title ^= 1; | ||||||
|                 break; |                 break; | ||||||
|             case 'l': |             case 'l': | ||||||
|                 ret->link ^= 1; |                 if(current_item == nullptr) | ||||||
|  |                     ret->link ^= 1; | ||||||
|  |                 else | ||||||
|  |                     current_item->link ^= 1; | ||||||
|                 break; |                 break; | ||||||
|             case 'd': |             case 'd': | ||||||
|                 ret->description ^= 1; |                 if(current_item == nullptr) | ||||||
|  |                     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': | ||||||
|                 ret->pubdate ^= 1; |                 if(current_item == nullptr) | ||||||
|  |                     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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Clortox
						Clortox