/*ident "@(#)Args:Args.c 3.1" */ /****************************************************************************** * * C++ Standard Components, Release 3.0. * * Copyright (c) 1991, 1992 AT&T and Unix System Laboratories, Inc. * Copyright (c) 1988, 1989, 1990 AT&T. All Rights Reserved. * * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T and Unix System * Laboratories, Inc. The copyright notice above does not evidence * any actual or intended publication of such source code. * ******************************************************************************/ #include "Argslib.h" Args::Args(int argc, const char*const* argv, const char* optstr_, int bits, const char*const* keywords) : opterr(0), firstopt(0), lastopt(0), firstarg(0), lastarg(0), optstr(optstr_), progname_(argv[0]), nargs_(0), plus(bits & plusoptions) { parse(argc, argv, bits & intermix, keywords); } int Args::isflag(char c) const { return (c == '-' || (plus && c == '+')); } void Args::parse(int argc, const char*const* argv, int mix, const char*const* keywords) { int i; for (i = 1; i < argc; ++i) { const char* ap = argv[i]; if (strcmp(ap, "--") == 0) { ++i; break; } if (isflag(*ap)) parse_block(argc, argv, i, keywords); else if (mix) addarg(argv[i]); else break; } for (; i < argc; ++i) { addarg(argv[i]); } } Args::~Args() { for (Opt* opt = firstopt; opt != 0; ) { Opt* next = opt->next; delete opt; opt = next; } for (Arg* arg = firstarg; arg != 0; ) { Arg* next = arg->next; delete arg; arg = next; } firstopt = lastopt = 0; firstarg = lastarg = 0; nargs_ = 0; } Subopt::Subopt(const char* n, const char* v) : name_(n), value_(v), next(0), prev(0) { } void Args::addarg(const char* p) { ++nargs_; Arg* arg = new Arg(p); if (lastarg == 0) { assert(firstarg == 0); firstarg = arg; } else { lastarg->next = arg; } lastarg = arg; } void Args::addopt_(Opt* opt) { opt->prev = lastopt; if (lastopt == 0) { assert(firstopt == 0); firstopt = opt; } else { lastopt->next = opt; } lastopt = opt; } void Args::addopt(char flag, const char* option, const char* value, int iskey) { if (iskey) addopt_(new Opt(flag, option, value)); else addopt_(new Opt(flag, *option, value)); } // warning: name and value might not yet be null terminated // (but they will eventually be by the caller) void Opt::addsubopt(char* name, char* value) { Subopt* subopt = new Subopt(name, value); subopt->prev = lastsubopt; if (lastsubopt == 0) { assert(firstsubopt == 0); firstsubopt = subopt; } else { lastsubopt->next = subopt; } lastsubopt = subopt; } Args::Opttype Args::opttype(char flag, char option) { const char* p = strchr(optstr, option); if (p == 0) { unexpected_opt_err(flag, option); return illegalopt; } else { switch (p[1]) { case valchar: return valueopt; case subchar: return suboptionsopt; default: return simpleopt; } } } // gets the value for option at ap in argv[i] // increments i if the value is argv[i+1] const char* Args::getvalue(int argc, const char*const* argv, int& i, char flag, const char* ap, int iskey) { if (!iskey && ap[1] != nul) { return ap+1; } else { if (++i >= argc) { missing_val_err(flag, ap, iskey); return 0; } const char* value = argv[i]; assert(value != 0); if (isflag(*value)) opt_as_val_err(value); return value; } } static char scanto(char*& p, const char* chars) { char* first = strpbrk(p, chars); if (first == 0) p += strlen(p); else p = first; return *p; } // build this option's suboptions from its value void Opt::build_subopts() { buf = new char [strlen(value_) + 1]; strcpy(buf, value_); for (char* p = buf; *p != nul; ) { char* name = p; char* subvalue; switch (scanto(p, ",=")) { case ',': addsubopt(name, p); *p++ = nul; break; case nul: addsubopt(name, p); break; case '=': *p++ = nul; subvalue = p; scanto(p, ","); addsubopt(name, subvalue); if (*p == ',') { *p++ = nul; } break; } } } void Args::process_option(int argc, const char*const* argv, int& i, char flag, const char* ap, Opttype ot, int iskey) { assert(ot != illegalopt); if (ot == simpleopt) { addopt(flag, ap, 0, iskey); } else { const char* value = getvalue(argc, argv, i, flag, ap, iskey); if (value != 0) { addopt(flag, ap, value, iskey); if (ot == suboptionsopt) lastopt->build_subopts(); } } } int Args::iskeyword_option(const char* opt, const char*const* keywords, Opttype& ot) { if (keywords == 0) return 0; int len = strlen(opt); assert(len > 0); int i = 0; const char* p; while ((p = keywords[i++]) != 0) { if (memcmp(opt, p, len) == 0) { switch(p[len]) { default: break; case nul: if (p[len-1] != valchar && p[len-1] != subchar) { ot = simpleopt; return 1; } break; case valchar: if (p[len+1] == nul) { ot = valueopt; return 1; } break; case subchar: if (p[len+1] == nul) { ot = suboptionsopt; return 1; } break; } } } return 0; } // parse argv[i] // increments i if argv[i+1] was an option value void Args::parse_block(int argc, const char*const* argv, int& i, const char*const* keywords) { Opttype ot; const char* ap = argv[i]; char flag = *ap++; if (*ap == nul) missing_opt_err(); else if (iskeyword_option(ap, keywords, ot)) process_option(argc, argv, i, flag, ap, ot, 1); else crack_block(argc, argv, i, flag, ap); } void Args::crack_block(int argc, const char*const* argv, int& i, char flag, const char* ap) { for (; *ap != nul; ++ap) { Opttype ot = opttype(flag, *ap);; if (ot) { if (ot != simpleopt && ap > argv[i]+1) { // value-taking options cannot appear in option blocks missing_val_err(flag, ap, 0); } else { process_option(argc, argv, i, flag, ap, ot, 0); if (ot != simpleopt) return; } } } } /////////////////////// // put here to overcome // cfront ={0} bug // Objection Args::unexpected_opt; Objection Args::missing_val; Objection Args::missing_opt; Objection Args::opt_as_val; // /////////////////////// #if 0 #include ostream& operator<<(ostream& os, const Args& a) { os << "options: "; for (Args::Opt* opt = a.firstopt; opt != 0; opt = opt->next) { os << "<" << opt->flag << opt->option << ", " << opt->value_ << "> "; } os << "\narguments: "; for (Args::Arg* arg = a.firstarg; arg != 0; arg = arg->next) { os << arg->p << " "; } return os; } #endif Args::Args(const Args &curr) : optstr(curr.optstr), progname_(curr.progname_), firstopt(0), lastopt(0), firstarg(0), lastarg(0) { opterr = curr.opterr; plus = curr.plus; nargs_ = curr.nargs_; for (Opt* opt = curr.firstopt; opt != 0; ) { Opt *tempopt = new Opt (*opt); tempopt->prev = lastopt; if (lastopt == 0) { firstopt = tempopt; } else { lastopt->next = tempopt; } lastopt = tempopt; opt = opt->next; } for (Arg* arg = curr.firstarg; arg != 0; ) { Arg *temparg = new Arg (*arg); if (lastarg == 0) { firstarg = temparg; } else { lastarg->next = temparg; } lastarg = temparg; arg = arg->next; } } Opt::Opt(const Opt &curr) : key(curr.key), value_(curr.value_), next(0), prev(0), buf(0), firstsubopt(0), lastsubopt(0) { flag_ = curr.flag_; chr_ = curr.chr_; if (curr.buf) { buf = new char[strlen(curr.buf)+1]; strcpy(buf, curr.buf); } for (Subopt* subopt = curr.firstsubopt; subopt != 0; ) { Subopt *tempsubopt = new Subopt (*subopt); tempsubopt->prev = lastsubopt; if (lastsubopt == 0) { firstsubopt = tempsubopt; } else { lastsubopt->next = tempsubopt; } lastsubopt = tempsubopt; subopt = subopt->next; } }