/*************************************************************************** commandline.cpp W. Michael Brown ------------------- Command line parsing stuff.. * Add argument with ' ' for arguments that do not use - (i.e. filenames) * Manditory for the ' ' requires only 1 argument regardless of the number - use argsize; begin : Sun Jun 11 2003 copyright : (C) 2003 by W. Michael Brown email : mbrown@nirvana.unm.edu ***************************************************************************/ #include "commandline.h" CommandLine::Parameter::Parameter() { num_args=0; manditory_args=0; manditory=false; dash=false; set=false; } CommandLine::Parameter::~Parameter() {} CommandLine::CommandLine() { help_set=false; progname=""; // Set up the default man chapters manchapter_order[0]="NAME"; man_chapters["NAME"].clear(); manchapter_order[1]="VERSION"; man_chapters["VERSION"].clear(); manchapter_order[2]="SYNOPSIS"; man_chapters["SYNOPSIS"].clear(); manchapter_order[3]="DESCRIPTION"; man_chapters["DESCRIPTION"].clear(); manchapter_order[4]="PARAMETERS"; man_chapters["PARAMETERS"].clear(); man_numchapters=5; } CommandLine::~CommandLine() { } void CommandLine::addargname(char n, const string &an) { parameters[n].argnames.push_back(an); } void CommandLine::adddescription(char n, const string &d) { parameters[n].description.push_back(d); } // Returns the argument size for a parameter unsigned CommandLine::argsize(char n) { return parameters[n].args.size(); } bool CommandLine::operator [](char n) { return set(n); } string CommandLine::program_name() { return progname; } string CommandLine::full_command_line() { return full_line; } // ----------------- Add allowed arguments void CommandLine::add(char n, unsigned num) { check(n); parameters[n].num_args=num; parameters[n].manditory_args=num; } // Where num represents maximum number of arguments and man_num represents // manditory number of arguments for a parameter void CommandLine::add(char n, unsigned num, unsigned man_num) { check(n); parameters[n].num_args=num; parameters[n].manditory_args=man_num; } void CommandLine::addmanditory(char n, unsigned num) { check(n); parameters[n].manditory_args=num; parameters[n].num_args=num; parameters[n].manditory=true; } // Where num represents maximum number of arguments and man_num represents // manditory number of arguments for a parameter void CommandLine::addmanditory(char n, unsigned num, unsigned man_num) { check(n); parameters[n].num_args=num; parameters[n].manditory_args=man_num; parameters[n].manditory=true; } // Allow parameter that takes signed numbers as input void CommandLine::addsigned(char n, unsigned num) { check(n); parameters[n].num_args=num; parameters[n].manditory_args=num; parameters[n].dash=true; // Allow dashes in arguments } // Allow parameter that takes signed numbers as input void CommandLine::addsigned(char n, unsigned num, unsigned man_num) { check(n); parameters[n].num_args=num; parameters[n].manditory_args=man_num; parameters[n].dash=true; // Allow dashes in arguments } void CommandLine::addhelp(char n, unsigned num) { check(n); parameters[n].num_args=num; parameters[n].manditory_args=num; help_set=true; help_param=n; } // Add descriptions for man pages void CommandLine::addargnames(char n, unsigned num, const string args[]) { for (unsigned i=0; i::iterator m; m=parameters.find(n); if (m!=parameters.end()) { cerr << "DEVELOPER ERROR: Parameter: " << n << " set twice!\n"; cerr << "commandline.h: Exiting...\n\n"; exit(1); } } bool CommandLine::optargparams() { map::iterator m; for (m=parameters.begin(); m!=parameters.end(); m++) if (m->second.manditory_argssecond.num_args) return true; return false; } // Returns the number of arguments that are not parameters (' ' name) unsigned CommandLine::argsize() { return parameters[' '].args.size(); } // Whether or not this parameter was set bool CommandLine::set(char n) { return parameters[n].set; } // Force a parameter to be unset void CommandLine::unset(char n) { parameters[n].set=false; } char* CommandLine::arg(char n, unsigned num) { return parameters[n].args[num]; } int CommandLine::argint(char n, unsigned num) { return atoi(parameters[n].args[num]); } double CommandLine::argdouble(char n, unsigned num) { return atof(parameters[n].args[num]); } string CommandLine::argstring(char n, unsigned num) { string s; s=parameters[n].args[num]; return s; } bool CommandLine::parse(int argc, char* argv[], Error *error) { unsigned i; map::iterator m; char flag; int parameter; // Set to the parameter that arguments are being parsed progname=a::filenameonly(argv[0]); full_line=string(argv[0]); for (unsigned i=1; iaddwarning(3,9,"CommandLine","Invalid Command Line Argument: "+ string(argv[argnum])); return false; } parameters[' '].set=true; parameters[' '].args.push_back(argv[argnum]); argnum++; continue; } // Set a parameter flag=argv[argnum][1]; m=parameters.find(flag); if (m==parameters.end()) { error->addwarning(4,9,"CommandLine","Invalid Command Line Parameter: "+ string(argv[argnum])); return false; } // Make sure all required arguments are set before parameters with // optional arguments if (m->second.manditory_argssecond.num_args) if (parameters[' '].args.size()buffer() << "Parameters with optional arguments must be " << "placed after manditory commandline arguments"; error->addbuf(5,9,"CommandLine"); return false; } parameter=argnum; argnum++; m->second.set=true; // Get the parameter arguments for (i=0; isecond.num_args; i++) { // Make sure we are not at the end of the parameter list if (argnum>=argc) if (m->second.args.size()second.manditory_args) { error->buffer() << "Invalid Number of Arguments: -" << m->first << " requires " << m->second.num_args << " arguments!"; error->addbuf(5,9,"CommandLine"); return false; } else break; // Assure the right number of arguments for signed numbers if (argv[argnum][0]=='-' && m->second.dash==true) if (!isdigit(argv[argnum][1])) if (m->second.args.size()second.manditory_args) { error->buffer() << "Invalid Number of Arguments: -" << m->first << " requires " << m->second.num_args << " arguments!"; error->addbuf(5,9,"CommandLine"); return false; } else break; // Assure the right number of arguments for other numbers if (argv[argnum][0]=='-' && m->second.dash==false) if (m->second.args.size()second.manditory_args) { error->buffer() << "Invalid Number of Arguments: -" << m->first << " requires " << m->second.num_args << " arguments!"; error->addbuf(5,9,"CommandLine"); return false; } else break; m->second.args.push_back(argv[argnum]); argnum++; } } // If help was set, we do not need to check for manditory args if (help_set) if (parameters[help_param].set) return true; // Assure that the manditory arguments were set for commandline if (parameters[' '].manditory) if (parameters[' '].args.size()addwarning(6,9,"CommandLine","Missing Required Argument!"); return false; } // Assure that manditory arguments were set for parameters! for (m=parameters.begin(); m!=parameters.end(); m++) { if (m->second.manditory) if (m->second.set==false) { error->buffer() << "Missing Required Argument: \n\n"; if (m->first!=' ') error->buffer() << "-" << m->first << " must be set!"; error->addbuf(7,9,"CommandLine"); return false; } } return true; } void CommandLine::write_man_page(ostream & out, const string &version, const string &header) { unsigned i; map::iterator m; string bold="\\fB"; string italic="\\fI"; string regular="\\fR"; out << ".TH " << program_name() << " 1 \"" << a::date() << "\"" << " \"" << program_name() << " (" << header << ") " << version << "\" \"" << header << '\"' << endl; // Go through the chapters map::iterator mc; for (mc=manchapter_order.begin(); mc!=manchapter_order.end(); mc++) { // NAME Section if (mc->second=="NAME") { out << ".SH NAME\n" << bold << program_name() << regular; if (man_chapters["NAME"].size()!=0) { out << " - "; for (i=0; isecond=="SYNOPSIS" && man_chapters["SYNOPSIS"].empty()) { out << ".PD 2\n.SH SYNOPSIS\n.PD 1\n.TP\n"; if (program_name().length()>6) out << bold << program_name() << regular << " "; else out << ".B " << program_name() << endl; out << format_synopsis(bold,italic,regular) << endl; if (program_name().length()>6) out << ".br\n"; if (parameters[' '].num_args!=0 && optargparams()) out << ".PD 2\n.PP\nParameters with optional arguments should be placed " << "after manditory commandline arguments.\n"; continue; } // end SYNOPSIS // PARAMETERS if (mc->second=="PARAMETERS") { if (!(parameters.size()==0 || (parameters.size()==1 && (parameters.begin())->first==' '))) { out << ".PD 2\n.SH PARAMETERS\n.PD 1\n"; for (m=parameters.begin(); m!=parameters.end(); m++) { if (m->first==' ') continue; out << ".TP\n"; out << format_parameter(m->first,bold,italic,regular) << endl; if (format_parameter(m->first,"","","").length()>6) out << ".PD 0\n.TP\n.PP\n.PD 1\n"; // Output the description vector fdesc=man_format(m->second.description,bold, italic,regular); for (i=0; isecond,bold,italic,regular); } } void CommandLine::writeman_chapter(ostream &out,const string &name, const string &bold, const string &italic, const string ®ular) { if (man_chapters[name].empty()) return; out << ".PD 2\n.SH " << name << "\n.PD 1\n"; vector formatted=man_format(man_chapters[name],bold,italic,regular); for (unsigned i=0; i::iterator m; bool space=false; s=format_parameter(' ',bold,italic,regular)+" "; for (m=parameters.begin(); m!=parameters.end(); m++) { if (m->first==' ') continue; if (space) s+=' '; space=true; if (m->second.manditory==false) s+='['; s+=format_parameter(m->first,bold,italic,regular); if (m->second.manditory==false) s+="]"; } // end for return s; } // Write a synopsis in plain text format fitted to a given column width void CommandLine::write_text_synopsis(ostream &out, unsigned column_width) { string s=format_synopsis("","",""); vector lines; a::format_fit(column_width-program_name().length()-1,s,lines); out << program_name() << " "; for (unsigned i=0; i=p.manditory_args) strp+='['; if (param!=' ') strp+=italic+p.argnames[i]+regular; else strp+=p.argnames[i]; if (i>=p.manditory_args) strp+=']'; } if (p.argnames.size() CommandLine::man_format(const vector &input, const string &bold, const string &italic, const string ®ular) { vector output; map::iterator m; for (unsigned i=0; ifirst!=' ') { string source="-"; source+=m->first; a::str_replace(source,bold+source+regular,temp); } for (unsigned j=0; jsecond.argnames.size(); j++) a::str_replace(m->second.argnames[j], italic+m->second.argnames[j]+regular,temp); } output.push_back(temp); } return output; }