diff -r 30113bfbe723 -r b3afb9f1e801 lib/cli/main.cc --- a/lib/cli/main.cc Sun Jan 20 00:12:17 2008 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,342 +0,0 @@ -// Copyright (C) 1999,2000 Bruce Guenter -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -#include -#include "ac/time.h" -#include "fdbuf/fdbuf.h" -#include -#include -#include "cli.h" - -#ifndef HAVE_SRANDOM -void srandom(unsigned int seed); -#endif - -static bool do_show_usage = false; -const char* argv0; -const char* argv0base; -const char* argv0dir; - -static cli_option help_option = { 'h', "help", cli_option::flag, - true, &do_show_usage, - "Display this help and exit", 0 }; - -static cli_option** options; -static unsigned optionc; - -static void build_options() -{ - for(optionc = 0; - cli_options[optionc].ch || cli_options[optionc].name; - optionc++) ; - optionc++; - options = new cli_option*[optionc]; - for(unsigned i = 0; i < optionc-1; i++) - options[i] = &cli_options[i]; - options[optionc-1] = &help_option; -} - -static inline unsigned max(unsigned a, unsigned b) -{ - return (a>b) ? a : b; -} - -static const char* fill(unsigned i) -{ - static unsigned lastlen = 0; - static char* buf = 0; - if(i > lastlen) { - delete[] buf; - buf = new char[i+1]; - lastlen = i; - } - memset(buf, ' ', i); - buf[i] = 0; - return buf; -} - -static void show_usage() -{ - fout << "usage: " << cli_program << " [flags] " << cli_args_usage << endl; -} - -static unsigned calc_max_width() -{ - // maxwidth is the maximum width of the long argument - unsigned maxwidth = 0; - for(unsigned i = 0; i < optionc; i++) { - unsigned width = 0; - cli_option* o = options[i]; - if(o->name) { - width += strlen(o->name); - switch(o->type) { - case cli_option::string: width += 6; break; - case cli_option::integer: width += 4; break; - case cli_option::uinteger: width += 4; break; - case cli_option::stringlist: width += 5; break; - case cli_option::flag: break; - case cli_option::counter: break; - } - } - if(width > maxwidth) - maxwidth = width; - } - return maxwidth; -} - -static void show_option(cli_option* o, unsigned maxwidth) -{ - if(o == &help_option) - fout << '\n'; - if(o->ch) - fout << " -" << o->ch; - else - fout << " "; - fout << (o->ch && o->name ? ", " : " "); - if(o->name) { - const char* extra = ""; - switch(o->type) { - case cli_option::string: extra = "=VALUE"; break; - case cli_option::integer: extra = "=INT"; break; - case cli_option::uinteger: extra = "=UNS"; break; - case cli_option::stringlist: extra = "=ITEM"; break; - case cli_option::flag: break; - case cli_option::counter: break; - } - fout << "--" << o->name << extra - << fill(maxwidth - strlen(o->name) - strlen(extra) + 2); - } - else - fout << fill(maxwidth+4); - fout << o->helpstr << '\n'; - if(o->defaultstr) - fout << fill(maxwidth+10) << "(Defaults to " << o->defaultstr << ")\n"; -} - -static void show_help() -{ - if(cli_help_prefix) - fout << cli_help_prefix; - unsigned maxwidth = calc_max_width(); - for(unsigned i = 0; i < optionc; i++) - show_option(options[i], maxwidth); - if(cli_help_suffix) - fout << cli_help_suffix; -} - -void usage(int exit_value, const char* errorstr) -{ - if(errorstr) - ferr << cli_program << ": " << errorstr << endl; - show_usage(); - show_help(); - exit(exit_value); -} - -cli_stringlist* stringlist_append(cli_stringlist* node, const char* newstr) -{ - cli_stringlist* newnode = new cli_stringlist(newstr); - if(node) { - cli_stringlist* head = node; - while(node->next) - node = node->next; - node->next = newnode; - return head; - } - else - return newnode; -} - -int cli_option::set(const char* arg) -{ - char* endptr; - switch(type) { - case flag: - *(int*)dataptr = flag_value; - return 0; - case counter: - *(int*)dataptr += flag_value; - return 0; - case integer: - *(int*)dataptr = strtol(arg, &endptr, 10); - if(*endptr) { - ferr << argv0 << ": invalid integer: " << arg << endl; - return -1; - } - return 1; - case uinteger: - *(unsigned*)dataptr = strtoul(arg, &endptr, 10); - if(*endptr) { - ferr << argv0 << ": invalid unsigned integer: " << arg << endl; - return -1; - } - return 1; - case stringlist: - *(cli_stringlist**)dataptr = - stringlist_append(*(cli_stringlist**)dataptr, arg); - return 1; - default: // string - *(const char**)dataptr = arg; - return 1; - } -} - -static int parse_short(int argc, char* argv[]) -{ - int end = strlen(argv[0]) - 1; - for(int i = 1; i <= end; i++) { - int ch = argv[0][i]; - unsigned j; - for(j = 0; j < optionc; j++) { - cli_option* o = options[j]; - if(o->ch == ch) { - if(o->type != cli_option::flag && - o->type != cli_option::counter) { - if(i < end) { - if(o->set(argv[0]+i+1) != -1) - return 0; - } - else if(argc <= 1) { - ferr << argv0 << ": option -" << o->ch - << " requires a value." << endl; - } - else - if(o->set(argv[1]) != -1) - return 1; - } - else if(o->set(0) != -1) - break; - return -1; - } - } - if(j >= optionc) { - ferr << argv0 << ": unknown option letter -" << argv[0][i] << endl; - return -1; - } - } - return 0; -} - -int cli_option::parse_long_eq(const char* arg) -{ - if(type == flag || type == counter) { - ferr << argv0 << ": option --" << name - << " does not take a value." << endl; - return -1; - } - else - return set(arg)-1; -} - -int cli_option::parse_long_noeq(const char* arg) -{ - if(type == flag || type == counter) - return set(0); - else if(arg) - return set(arg); - else { - ferr << argv0 << ": option --" << name - << " requires a value." << endl; - return -1; - } -} - -static int parse_long(int, char* argv[]) -{ - const char* arg = argv[0]+2; - for(unsigned j = 0; j < optionc; j++) { - cli_option* o = options[j]; - if(o->name) { - size_t len = strlen(o->name); - if(!memcmp(arg, o->name, len)) { - if(arg[len] == '\0') - return o->parse_long_noeq(argv[1]); - else if(arg[len] == '=') - return o->parse_long_eq(arg+len+1); - } - } - } - ferr << argv0 << ": unknown option string: '--" << arg << "'" << endl; - return -1; -} - -static int parse_args(int argc, char* argv[]) -{ - build_options(); - int i; - for(i = 1; i < argc; i++) { - const char* arg = argv[i]; - // Stop at the first non-option argument - if(arg[0] != '-') - break; - // Stop after the first "-" or "--" - if(arg[1] == '\0' || - (arg[1] == '-' && arg[2] == '\0')) { - i++; - break; - } - int j = (arg[1] != '-') ? - parse_short(argc-i, argv+i) : - parse_long(argc-i, argv+i); - if(j < 0) - usage(1); - else - i += j; - } - return i; -} - -static void set_argv0(const char* p) -{ - argv0 = p; - static const char* empty = ""; - const char* s = strrchr(p, '/'); - if(s) { - ++s; - argv0base = s; - size_t length = s-p; - char* tmp = new char[length+1]; - memcpy(tmp, p, length); - tmp[length] = 0; - argv0dir = tmp; - } - else { - argv0base = p; - argv0dir = empty; - } -} - -int main(int argc, char* argv[]) -{ - struct timeval tv; - gettimeofday(&tv, 0); - srandom(tv.tv_usec ^ tv.tv_sec); - - set_argv0(argv[0]); - int lastarg = parse_args(argc, argv); - - if(do_show_usage) - usage(0); - - argc -= lastarg; - argv += lastarg; - if(argc < cli_args_min) - usage(1, "Too few command-line arguments"); - if(cli_args_max >= cli_args_min && argc > cli_args_max) - usage(1, "Too many command-line arguments"); - - return cli_main(argc, argv); -}