summaryrefslogblamecommitdiffstatshomepage
path: root/src/lib/netlist/plib/poptions.cpp
blob: 6f6ace0599c2bfce10e48ea54ddaf6c6676ee4ca (plain) (tree)
1
2
3
4
5
6
7
8
9

                               

                     
                       
                     
                   

                
 
                                                                      
                      



                                             
                                                                                                                            

                                                                    


         
                                                      




                                 
                                                       
         
                                     



                             
                                                      





                                          
                          
                               
         

         

                                    



                                       
                                              



                            
                                                       
         
                                      

         
                                         
         











                                                                                  
                                                                                                                     






                                                                          
                                                                                                                    


                                 

         
                                                 
         


                                             


                                       
                                             



                                                   
                                                                            
                         
                                                                   
                                                           
                                 




                                                                                              
                                                                                






                                                                         
                                 
                         
                                                                                
                         

                                                                     
                                    
                                                     

                                                             
                                                                
                                 

                            
                         




                                                                           
                         





                                                  
                                                                        



                                                         


                                                             
                                                                                 






                                                             
                                                  





                            
                                                                                               
                                                  
         
                                                    



                                          
                                                                                               
                                                      
                         
                                                                       

                                                           
                                                                                             







                                                

                                                                               



                                                                        
                                                               
 
                                              
                 



                                                                                   
                                                                       
                         



                                                                         
                                 





                                                                       
                                         
                                                            
                                                                                                      
                                                       
                                                 



                                                                                   
                                                                                                   
                                                 

                                                                        
                                         
                                 
                                                                                         
                                                           






                                                                                                      
                         
                                                                                  
                         

                                                                                                                
                         
                 
                                        








                                                                                            
                                    

                                                        



                           
                                                               
         
                                             
                 
                                                                   
                                                                        



                                           
                                                              
         
                                             
                 
                                                                   
                                                                      





                                           
 
// license:GPL-2.0+
// copyright-holders:Couriersud

#include "poptions.h"
#include "pexception.h"
#include "pstrutil.h"
#include "ptypes.h"

namespace plib {

	option_base::option_base(options &parent, const pstring &help)
	: m_help(help)
	{
		parent.register_option(this);
	}

	option::option(options &parent, const pstring &ashort, const pstring &along, const pstring &help, bool has_argument)
	: option_base(parent, help), m_short(ashort), m_long(along),
	  m_has_argument(has_argument), m_specified(false)
	{
	}

	int option_str::parse(const pstring &argument)
	{
		m_val = argument;
		return 0;
	}

	int option_bool::parse(const pstring &argument)
	{
		unused_var(argument);
		m_val = true;
		return 0;
	}

	int option_vec::parse(const pstring &argument)
	{
		bool err = false;
		m_val.push_back(argument);
		return (err ? 1 : 0);
	}

	options::options()
	: m_other_args(nullptr)
	{
	}

	options::options(option **o)
	: m_other_args(nullptr)
	{
		int i=0;
		while (o[i] != nullptr)
		{
			register_option(o[i]);
			i++;
		}
	}

	void options::register_option(option_base *opt)
	{
		m_opts.push_back(opt);
	}

	void options::check_consistency()
	{
		for (auto &opt : m_opts)
		{
			auto *o = dynamic_cast<option *>(opt);
			if (o != nullptr)
			{
				if (o->short_opt() == "" && o->long_opt() == "")
				{
					auto *ov = dynamic_cast<option_args *>(o);
					if (ov != nullptr)
					{
						if (m_other_args != nullptr)
						{
							pthrow<pexception>("other args can only be specified once!");
						}
						else
						{
							m_other_args = ov;
						}
					}
					else
						pthrow<pexception>("found option with neither short or long tag!" );
				}
			}
		}
	}

	int options::parse(int argc, char **argv)
	{
		check_consistency();
		m_app = pstring(argv[0]);
		bool seen_other_args = false;

		for (int i=1; i<argc; )
		{
			pstring arg(argv[i]);
			option *opt = nullptr;
			pstring opt_arg;
			bool has_equal_arg = false;

			if (!seen_other_args && plib::startsWith(arg, "--"))
			{
				auto v = psplit(arg.substr(2),"=");
				if (v.size() && v[0] != "")
				{
					opt = getopt_long(v[0]);
					has_equal_arg = (v.size() > 1);
					if (has_equal_arg)
					{
						for (std::size_t j = 1; j < v.size() - 1; j++)
							opt_arg += (v[j] + "=");
						opt_arg += v[v.size()-1];
					}
				}
				else
				{
					opt = m_other_args;
					seen_other_args = true;
				}
			}
			else if (!seen_other_args && plib::startsWith(arg, "-"))
			{
				std::size_t p = 1;
				opt = getopt_short(arg.substr(p, 1));
				++p;
				if (p < arg.length())
				{
					has_equal_arg = true;
					opt_arg = arg.substr(p);
				}
			}
			else
			{
				seen_other_args = true;
				if (m_other_args == nullptr)
					return i;
				opt = m_other_args;
				i--; // we haven't had an option specifier;
			}
			if (opt == nullptr)
				return i;
			if (opt->has_argument())
			{
				if (has_equal_arg)
				{
					if (opt->do_parse(opt_arg) != 0)
						return i;
				}
				else
				{
					i++;
					if (i >= argc)
						return i - 1;
					if (opt->do_parse(pstring(argv[i])) != 0)
						return i - 1;
				}
			}
			else
			{
				if (has_equal_arg)
					return i;
				opt->do_parse("");
			}
			i++;
		}
		return argc;
	}

	pstring options::split_paragraphs(const pstring &text, unsigned width, unsigned indent,
			unsigned firstline_indent)
	{
		auto paragraphs = psplit(text,"\n");
		pstring ret("");

		for (auto &p : paragraphs)
		{
			pstring line = plib::rpad(pstring(""), pstring(" "), firstline_indent);
			for (auto &s : psplit(p, " "))
			{
				if (line.length() + s.length() > width)
				{
					ret += line + "\n";
					line = plib::rpad(pstring(""), pstring(" "), indent);
				}
				line += s + " ";
			}
			ret += line + "\n";
		}
		return ret;
	}

	pstring options::help(const pstring &description, const pstring &usage,
			unsigned width, unsigned indent) const
	{
		pstring ret;

		ret = split_paragraphs(description, width, 0, 0) + "\n";
		ret += "Usage:\t" + usage + "\n\nOptions:\n\n";

		for (auto & optbase : m_opts )
		{
			// Skip anonymous inputs which are collected in option_args
			if (dynamic_cast<option_args *>(optbase) != nullptr)
				continue;

			if (auto opt = dynamic_cast<option *>(optbase))
			{
				pstring line = "";
				if (opt->short_opt() != "")
					line += "  -" + opt->short_opt();
				if (opt->long_opt() != "")
				{
					if (line != "")
						line += ", ";
					else
						line = "      ";
					line += "--" + opt->long_opt();
					if (opt->has_argument())
					{
						line += "=";
						auto *ol = dynamic_cast<option_str_limit_base *>(opt);
						if (ol)
						{
							for (auto &v : ol->limit())
							{
								line += v + "|";
							}
							line = plib::left(line, line.length() - 1);
						}
						else
							line += "Value";
					}
				}
				line = plib::rpad(line, pstring(" "), indent - 2) + "  ";
				if (line.length() > indent)
				{
					//ret += "TestGroup abc\n  def gef\nxyz\n\n" ;
					ret += line + "\n";
					ret += split_paragraphs(opt->help(), width, indent, indent);
				}
				else
					ret += split_paragraphs(line + opt->help(), width, indent, 0);
			}
			else if (auto grp = dynamic_cast<option_group *>(optbase))
			{
				ret += "\n" + grp->group() + ":\n";
				if (grp->help() != "") ret += split_paragraphs(grp->help(), width, 4, 4) + "\n";
			}
		}
		// FIXME: other help ...
		pstring ex("");
		for (auto & optbase : m_opts )
		{
			if (auto example = dynamic_cast<option_example *>(optbase))
			{
				ex += "> " + example->example()+"\n\n";
				ex += split_paragraphs(example->help(), width, 4, 4) + "\n";
			}
		}
		if (ex.length() > 0)
		{
			ret += "\n\nExamples:\n\n" + ex;
		}
		return ret;
	}

	option *options::getopt_short(const pstring &arg) const
	{
		for (auto & optbase : m_opts)
		{
			auto opt = dynamic_cast<option *>(optbase);
			if (opt && arg != "" && opt->short_opt() == arg)
				return opt;
		}
		return nullptr;
	}
	option *options::getopt_long(const pstring &arg) const
	{
		for (auto & optbase : m_opts)
		{
			auto opt = dynamic_cast<option *>(optbase);
			if (opt && arg !="" && opt->long_opt() == arg)
				return opt;
		}
		return nullptr;
	}

} // namespace plib