rss-cli/src/options.cpp

339 lines
15 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Tyler Perkins
// 7-23-21
// options implementation
//
#include "options.hpp"
void help(char* progName){
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 URI of the rss stream\n";
std::cout << " Also accepts '-' to take input\n";
std::cout << " from stdin (stops once a newline is reached)\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 << " [-L, --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 << " [-e, --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";
std::cout << " [-Q, --imageurl] Get channel image URL\n";
std::cout << " [-I, --imagetitle] Get image title, same as ALT in html\n";
std::cout << " [-E, --imagelink] Get link to site, image will act as a link\n";
std::cout << " [-W, --imagewidth] Get width of image\n";
std::cout << " [-H, --imageheight] Get height of image\n";
std::cout << " [-D, --clouddomain] Get domain of feed update service\n";
std::cout << " [-P, --cloudport] Get port of feed update service\n";
std::cout << " [-A, --cloudpath] Get path to access for feed update service\n";
std::cout << " [-R, --cloudregister] Get register procedure for feed update service\n";
std::cout << " [-O, --cloudprotocol] Get protocol feed update service uses\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 << " [-C, --category] Get category list\n";
std::cout << " [-f, --comments] Get link to comments\n";
std::cout << " [-G, --guid] Get GUID\n";
std::cout << " [-p, --pubdate] Get publishing date\n";
std::cout << " [-s, --source] Get source of item\n";
std::cout << " [-U, --enclosureurl] Get enclosure URL\n";
std::cout << " [-T, --enclosuretype] Get enclosure MIME type\n";
std::cout << " [-K, --enclosurelength]Get enclosure length, in bytes\n\n";
std::cout << "General options:\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);
}
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);
if(c == -1)
break;
switch(c){
case 'u':
ret->uri = std::string(optarg);
break;
case 't':
if(current_item == nullptr)
ret->title ^= 1;
else
current_item->title ^= 1;
break;
case 'l':
if(current_item == nullptr)
ret->link ^= 1;
else
current_item->link ^= 1;
break;
case 'd':
if(current_item == nullptr)
ret->description ^= 1;
else
current_item->description ^= 1;
break;
case 'L':
if(current_item == nullptr)
ret->language ^= 1;
else
std::cerr << "-L option not understood in context of --item; ignoring" << std::endl;
break;
case 'm':
if(current_item == nullptr)
ret->webmaster ^= 1;
else
std::cerr << "-m option not understood in context of --item; ignoring" << std::endl;
break;
case 'c':
if(current_item == nullptr)
ret->copyright ^= 1;
else
std::cerr << "-c option not understood in context of --item; ignoring" << std::endl;
break;
case 'p':
if(current_item == nullptr)
ret->pubdate ^= 1;
else
current_item->pubdate ^= 1;
break;
case 'e':
if(current_item == nullptr)
ret->managingeditor ^= 1;
else
std::cerr << "-e option not understood in context of --item; ignoring" << std::endl;
break;
case 'g':
if(current_item == nullptr)
ret->generator ^= 1;
else
std::cerr << "-g option not understood in context of --item; ignoring" << std::endl;
break;
case 'o':
if(current_item == nullptr)
ret->docs ^= 1;
else
std::cerr << "-o option not understood in context of --item; ignoring" << std::endl;
break;
case 'w':
if(current_item == nullptr)
ret->ttl ^= 1;
else
std::cerr << "-w option not understood in context of --item; ignoring" << std::endl;
break;
case 'b':
if(current_item == nullptr)
ret->builddate ^= 1;
else
std::cerr << "-b option not understood in context of --item; ignoring" << std::endl;
break;
case 'Q':
if(current_item == nullptr)
ret->imageurl ^= 1;
else
std::cerr << "-Q option not understood in context of --item; ignoring" << std::endl;
break;
case 'I':
if(current_item == nullptr)
ret->imagetitle ^= 1;
else
std::cerr << "-I option not understood in context of --item; ignoring" << std::endl;
break;
case 'E':
if(current_item == nullptr)
ret->imagelink ^= 1;
else
std::cerr << "-E option not understood in context of --item; ignoring" << std::endl;
break;
case 'W':
if(current_item == nullptr)
ret->imagewidth ^= 1;
else
std::cerr << "-I option not understood in context of --item; ignoring" << std::endl;
break;
case 'H':
if(current_item == nullptr)
ret->imageheight ^= 1;
else
std::cerr << "-I option not understood in context of --item; ignoring" << std::endl;
break;
case 'D':
if(current_item == nullptr)
ret->clouddomain ^= 1;
else
std::cerr << "-I option not understood in context of --item; ignoring" << std::endl;
break;
case 'P':
if(current_item == nullptr)
ret->cloudport ^= 1;
else
std::cerr << "-I option not understood in context of --item; ignoring" << std::endl;
break;
case 'A':
if(current_item == nullptr)
ret->cloudpath ^= 1;
else
std::cerr << "-I option not understood in context of --item; ignoring" << std::endl;
break;
case 'R':
if(current_item == nullptr)
ret->cloudregister ^= 1;
else
std::cerr << "-I option not understood in context of --item; ignoring" << std::endl;
break;
case 'O':
if(current_item == nullptr)
ret->cloudprotocol ^= 1;
else
std::cerr << "-I option not understood in context of --item; ignoring" << std::endl;
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 'C':
if(current_item == nullptr){
std::cerr << "Invalid option in this context: [-C --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 'G':
if(current_item == nullptr){
std::cerr << "Invalid option in this context: [-G --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 'U':
if(current_item == nullptr){
std::cerr << "Invalid option in this context: [-U --enclosureurl]" << std::endl;
std::cerr << "Did you provide the [-i --index] flag first?" << std::endl;
} else
current_item->enclosureurl ^= 1;
break;
case 'T':
if(current_item == nullptr){
std::cerr << "Invalid option in this context: [-T --enclosuretype]" << std::endl;
std::cerr << "Did you provide the [-i --index] flag first?" << std::endl;
} else
current_item->enclosuretype ^= 1;
break;
case 'K':
if(current_item == nullptr){
std::cerr << "Invalid option in this context: [-K --enclosurelength]" << std::endl;
std::cerr << "Did you provide the [-i --index] flag first?" << std::endl;
} else
current_item->enclosurelength ^= 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;
default:
abort();
}
}
if(ret->uri == ""){
std::cerr << "Missing required option! -u/--uri" << std::endl;
exit(-1);
}
return ret;
}