/* * Copyright 1995, 1996 Perforce Software. All rights reserved. * * This file is part of Perforce - the FAST SCM System. */ # include <stdhdrs.h> # include <error.h> # include <errornum.h> # include <msgsupp.h> # include <strbuf.h> # include "options.h" /* * option.cc - command line option processing * * {o >o * \<>) "Process command line options as defined in <option.h>. */ /* * Table of long-form options and their behavior. The second column in this * table must be unique (that is, each long-form option should only be listed * once), but the other columns are not unique. * * The rows in this table can be in any order, but we look them up linearly * so arguably the most common options should be toward the front. * * Note: Not all long-form options have corresponding single-character forms. * In general, the ones that do are the ones for the single-letter flags * that existed prior to the introduction of long-form options in 2014.1 */ Options::OptionInfo Options::list[] = { "change", Options::Change, 'c', ':', &MsgSupp::OptionChange, "port", Options::Port, 'p', ':', &MsgSupp::OptionPort, "user", Options::User, 'u', ':', &MsgSupp::OptionUser, "client", Options::Client, 'c', ':', &MsgSupp::OptionClient, "preview", Options::Preview, 'n', 0, &MsgSupp::OptionPreview, "delete", Options::Delete, 'd', 0, &MsgSupp::OptionDelete, "force", Options::Force, 'f', 0, &MsgSupp::OptionForce, "input", Options::Input, 'i', 0, &MsgSupp::OptionInput, "output", Options::Output, 'o', 0, &MsgSupp::OptionOutput, "max", Options::Max, 'm', '#', &MsgSupp::OptionMax, "quiet", Options::Quiet, 'q', 0, &MsgSupp::OptionQuiet, "short", Options::Short, 's', 0, &MsgSupp::OptionShort, "long", Options::Long, 'l', 0, &MsgSupp::OptionLong, "all", Options::All, 'a', 0, &MsgSupp::OptionAll, "filetype", Options::Filetype, 't', ':', &MsgSupp::OptionFiletype, "stream", Options::Stream, 'S', ':', &MsgSupp::OptionStream, "shelf", Options::Shelf, 's', ':', &MsgSupp::OptionShelf, "diff-flags", Options::DiffFlags, 'd', ':', &MsgSupp::OptionDiffFlags, "tags", Options::Tags, 'T', ':', &MsgSupp::OptionTags, "filter", Options::Filter, 'F', ':', &MsgSupp::OptionFilter, "parent", Options::Parent, 'P', ':', &MsgSupp::OptionParent, "inherited", Options::Inherited, 'i', 0, &MsgSupp::OptionInherited, "shelved", Options::Shelved, 'S', 0, &MsgSupp::OptionShelved, "show-time", Options::ShowTime, 't', 0, &MsgSupp::OptionShowTime, "brief", Options::Brief, 'L', 0, &MsgSupp::OptionBrief, "status", Options::ChangeStatus, 's', ':', &MsgSupp::OptionChangeStatus, "client", Options::ClientName, 'C', ':', &MsgSupp::OptionClientName, "host", Options::Host, 'H', ':', &MsgSupp::OptionHost, "password", Options::Password, 'P', ':', &MsgSupp::OptionPassword, "charset", Options::Charset, 'C', ':', &MsgSupp::OptionCharset, "command-charset", Options::CmdCharset, 'Q', ':', &MsgSupp::OptionCmdCharset, "variable", Options::Variable, 'v', ':', &MsgSupp::OptionVariable, "help", Options::Help, 'h', 0, &MsgSupp::OptionHelp, "version", Options::Version, 'V', 0, &MsgSupp::OptionVersion, "batchsize", Options::Batchsize, 'b', '#', &MsgSupp::OptionBatchsize, "blocksize", Options::Blocksize, 'b', '#', &MsgSupp::OptionBlocksize, "message-type", Options::MessageType, 's', 0, &MsgSupp::OptionMessageType, "xargs", Options::Xargs, 'x', ':', &MsgSupp::OptionXargs, "exclusive", Options::Exclusive, 'x', 0, &MsgSupp::OptionExclusive, "progress", Options::Progress, 'I', 0, &MsgSupp::OptionProgress, "compress", Options::Compress, 'z', 0, &MsgSupp::OptionCompress, "downgrade", Options::Downgrade, 'd', 0, &MsgSupp::OptionDowngrade, "directory", Options::Directory, 'd', ':', &MsgSupp::OptionDirectory, "retries", Options::Retries, 'r', '#', &MsgSupp::OptionRetries, "no-ignore", Options::NoIgnore, 'I', 0, &MsgSupp::OptionNoIgnore, "central-only", Options::CentralUsers, 'c', 0, &MsgSupp::OptionCentralUsers, "replica-only", Options::ReplicaUsers, 'r', 0, &MsgSupp::OptionReplicaUsers, "branch", Options::Branch, 'b', ':', &MsgSupp::OptionBranch, "reverse", Options::Reverse, 'r', 0, &MsgSupp::OptionReverse, "full-branch", Options::FullBranch, 'r', 0, &MsgSupp::OptionFullBranch, "status", Options::SpecFixStatus,'s', 0, &MsgSupp::OptionSpecFixStatus, "type", Options::ChangeType, 't', ':', &MsgSupp::OptionChangeType, "update", Options::ChangeUpdate, 'u', 0, &MsgSupp::OptionChangeUpdate, "original", Options::Original, 'O', 0, &MsgSupp::OptionOriginal, "new-user", Options::ChangeUser, 'U', 0, &MsgSupp::OptionChangeUser, "template", Options::Template, 't', ':', &MsgSupp::OptionTemplate, "switch", Options::Switch, 's', 0, &MsgSupp::OptionSwitch, "temporary", Options::Temporary, 'x', 0, &MsgSupp::OptionTemporary, "owner", Options::Owner, 'a', 0, &MsgSupp::OptionOwner, "administrator", Options::Administrator,'A', 0, &MsgSupp::OptionAdministrator, "global", Options::Global, 'g', 0, &MsgSupp::OptionGlobal, "type", Options::StreamType, 't', ':', &MsgSupp::OptionStreamType, "virtual", Options::VirtualStream,'v', 0, &MsgSupp::OptionVirtualStream, "client", Options::LimitClient, 'C', 0, &MsgSupp::OptionLimitClient, "label", Options::LabelName, 'l', ':', &MsgSupp::OptionLabelName, "summary", Options::Summary, 's', 0, &MsgSupp::OptionSummary, "global", Options::RunOnMaster, 'M', 0, &MsgSupp::OptionRunOnMaster, "human", Options::Human1024, 'h', 0, &MsgSupp::OptionHuman1024, "human-1000", Options::Human1000, 'H', 0, &MsgSupp::OptionHuman1000, "omit-lazy", Options::OmitLazy, 'z', 0, &MsgSupp::OptionOmitLazy, "leave-keywords", Options::LeaveKeywords,'k', 0, &MsgSupp::OptionLeaveKeywords, "file", Options::OutputFile, 'o', ':', &MsgSupp::OptionOutputFile, "input-file", Options::InputFile, 'i', ':', &MsgSupp::OptionInputFile, "archive", Options::Archive, 'A', 0, &MsgSupp::OptionArchive, "unload", Options::Unload, 'U', 0, &MsgSupp::OptionUnload, "exists", Options::Exists, 'e', 0, &MsgSupp::OptionExists, "content", Options::Content, 'h', 0, &MsgSupp::OptionContent, "omit-promoted", Options::OmitPromoted, 'p', 0, &MsgSupp::OptionOmitPromoted, "omit-moved", Options::OmitMoved, '1', 0, &MsgSupp::OptionOmitMoved, "keep-client", Options::KeepClient, 'k', 0, &MsgSupp::OptionKeepClient, "file-charset", Options::FileCharset, 'Q', ':', &MsgSupp::OptionFileCharset, "virtual", Options::Virtual, 'v', 0, &MsgSupp::OptionVirtual, "generate", Options::Generate, 'g', 0, &MsgSupp::OptionGenerate, "usage", Options::Usage, 'u', 0, &MsgSupp::OptionUsage, "job", Options::Job, 'j', ':', &MsgSupp::OptionJob, "expression", Options::Expression, 'e', ':', &MsgSupp::OptionExpression, "no-case-expression", Options::NoCaseExpr, 'E', ':', &MsgSupp::OptionNoCaseExpr, "increment", Options::Increment, 'i', 0, &MsgSupp::OptionIncrement, "fix-status", Options::FixStatus, 's', ':', &MsgSupp::OptionFixStatus, "replace", Options::Replace, 'r', 0, &MsgSupp::OptionReplace, "shelve-options", Options::ShelveOpts, 'a', ':', &MsgSupp::OptionShelveOpts, "submit-options", Options::SubmitOpts, 'f', ':', &MsgSupp::OptionSubmitOpts, "shelf", Options::SubmitShelf, 'e', ':', &MsgSupp::OptionSubmitShelf, "reopen", Options::Reopen, 'r', 0, &MsgSupp::OptionReopen, "description", Options::Description, 'd', ':', &MsgSupp::OptionDescription, "date", Options::Date, 'd', ':', &MsgSupp::OptionDate, "tamper-check", Options::Tamper, 't', 0, &MsgSupp::OptionTamper, "stream", Options::StreamName, 's', ':', &MsgSupp::OptionStreamName, "erase", Options::Wipe, 'w', 0, &MsgSupp::OptionWipe, "unchanged", Options::Unchanged, 'a', 0, &MsgSupp::OptionUnchanged, "depot", Options::Depot, 'D', ':', &MsgSupp::OptionDepot, "keep-head", Options::KeepHead, 'h', 0, &MsgSupp::OptionKeepHead, "purge", Options::Purge, 'p', 0, &MsgSupp::OptionPurge, "force-text", Options::ForceText, 't', 0, &MsgSupp::OptionForceText, "binary-as-text", Options::BinaryAsText, 't', 0, &MsgSupp::OptionBinaryAsText, "bypass-flow", Options::BypassFlow, 'F', 0, &MsgSupp::OptionBypassFlow, "show-change", Options::ShowChange, 'c', 0, &MsgSupp::OptionShowChange, "follow-branch", Options::FollowBranch, 'i', 0, &MsgSupp::OptionFollowBranch, "follow-integ", Options::FollowInteg, 'I', 0, &MsgSupp::OptionFollowInteg, "source-file", Options::SourceFile, 's', ':', &MsgSupp::OptionSourceFile, "output-flags", Options::OutputFlags, 'O', ':', &MsgSupp::OptionOutputFlags, "resolve-flags", Options::ResolveFlags, 'A', ':', &MsgSupp::OptionResolveFlags, "accept-flags", Options::AcceptFlags, 'a', ':', &MsgSupp::OptionAcceptFlags, "integ-flags", Options::IntegFlags, 'R', ':', &MsgSupp::OptionIntegFlags, "delete-flags", Options::DeleteFlags, 'D', ':', &MsgSupp::OptionDeleteFlags, "restrict-flags", Options::RestrictFlags,'R', ':', &MsgSupp::OptionRestrictFlags, "sort-flags", Options::SortFlags, 'S', ':', &MsgSupp::OptionSortFlags, "force-flag", Options::ForceFlag, 'F', ':', &MsgSupp::OptionForceFlag, "use-list", Options::UseList, 'L', 0, &MsgSupp::OptionUseList, "publish", Options::Publish, 'p', 0, &MsgSupp::OptionPublish, "safe", Options::Safe, 's', 0, &MsgSupp::OptionSafe, "group", Options::IsGroup, 'g', 0, &MsgSupp::OptionIsGroup, "user", Options::IsUser, 'u', 0, &MsgSupp::OptionIsUser, "owner", Options::IsOwner, 'o', 0, &MsgSupp::OptionIsOwner, "verbose", Options::Verbose, 'v', 0, &MsgSupp::OptionVerbose, "line-number", Options::LineNumber, 'n', 0, &MsgSupp::OptionLineNumber, "invert-match", Options::InvertMatch, 'v', 0, &MsgSupp::OptionInvertMatch, "files-with-matches", Options::FilesWithMatches,'l', 0, &MsgSupp::OptionFilesWithMatches, "files-without-match",Options::FilesWithoutMatch,'L', 0, &MsgSupp::OptionFilesWithoutMatch, "no-messages", Options::NoMessages, 's', 0, &MsgSupp::OptionNoMessages, "fixed-strings", Options::FixedStrings, 'F', 0, &MsgSupp::OptionFixedStrings, "basic-regexp", Options::BasicRegexp, 'G', 0, &MsgSupp::OptionBasicRegexp, "extended-regexp", Options::ExtendedRegexp,'E', 0, &MsgSupp::OptionExtendedRegexp, "perl-regexp", Options::PerlRegexp, 'P', 0, &MsgSupp::OptionPerlRegexp, "regexp", Options::Regexp, 'e', ':', &MsgSupp::OptionRegexp, "after-context", Options::AfterContext, 'A', ':', &MsgSupp::OptionAfterContext, "before-context", Options::BeforeContext,'B', ':', &MsgSupp::OptionBeforeContext, "context", Options::Context, 'C', ':', &MsgSupp::OptionContext, "ignore-case", Options::IgnoreCase, 'i', 0, &MsgSupp::OptionIgnoreCase, "journal-prefix", Options::JournalPrefix,'J', ':', &MsgSupp::OptionJournalPrefix, "repeat", Options::Repeat, 'i', '#', &MsgSupp::OptionRepeat, "backoff", Options::Backoff, 'b', '#', &MsgSupp::OptionBackoff, "archive-data", Options::ArchiveData, 'u', 0, &MsgSupp::OptionArchiveData, "status", Options::Status, 'l', 0, &MsgSupp::OptionStatus, "status", Options::LoginStatus, 's', 0, &MsgSupp::OptionLoginStatus, "local-journal", Options::LocalJournal, 'L', 0, &MsgSupp::OptionLocalJournal, "journal-position", Options::JournalPosition, 'j', 0, &MsgSupp::OptionJournalPosition, "serverid", Options::PullServerid, 'P', ':', &MsgSupp::OptionPullServerid, "exclude-tables", Options::ExcludeTables,'T', ':', &MsgSupp::OptionExcludeTables, "file", Options::File, 'f', ':', &MsgSupp::OptionFile, "revision", Options::Revision, 'r', ':', &MsgSupp::OptionRevision, "append", Options::Append, 'a', 0, &MsgSupp::OptionAppend, "sequence", Options::Sequence, 'c', ':', &MsgSupp::OptionSequence, "counter", Options::Counter, 't', ':', &MsgSupp::OptionCounter, "host", Options::HostName, 'h', ':', &MsgSupp::OptionHostName, "print", Options::Print, 'p', 0, &MsgSupp::OptionPrint, "start", Options::StartPosition,'s', '#', &MsgSupp::OptionStartPosition, "encoded", Options::Encoded, 'e', 0, &MsgSupp::OptionEncoded, "log", Options::LogName, 'l', ':', &MsgSupp::OptionLogName, "compress-ckp", Options::CompressCkp, 'Z', 0, &MsgSupp::OptionCompressCkp, "spec", Options::SpecType, 's', ':', &MsgSupp::OptionSpecType, "max-access", Options::MaxAccess, 'm', 0, &MsgSupp::OptionMaxAccess, "group", Options::GroupName, 'g', ':', &MsgSupp::OptionGroupName, "show-files", Options::ShowFiles, 'f', 0, &MsgSupp::OptionShowFiles, "name", Options::Name, 'n', ':', &MsgSupp::OptionName, "value", Options::Value, 'v', ':', &MsgSupp::OptionValue, "propagating", Options::Propagating, 'p', 0, &MsgSupp::OptionPropagating, "add", Options::OpenAdd, 'a', 0, &MsgSupp::OptionOpenAdd, "edit", Options::OpenEdit, 'e', 0, &MsgSupp::OptionOpenEdit, "delete", Options::OpenDelete, 'd', 0, &MsgSupp::OptionOpenDelete, "modtime", Options::UseModTime, 'm', 0, &MsgSupp::OptionUseModTime, "local", Options::Local, 'l', 0, &MsgSupp::OptionLocal, "output-base", Options::OutputBase, 'o', 0, &MsgSupp::OptionOutputBase, "system", Options::System, 's', 0, &MsgSupp::OptionSystem, "service", Options::Service, 'S', ':', &MsgSupp::OptionService, "histogram", Options::Histogram, 'h', 0, &MsgSupp::OptionHistogram, "table-not-unlocked", Options::TableNotUnlocked,'U', 0, &MsgSupp::OptionTableNotUnlocked, "table", Options::TableName, 't', ':', &MsgSupp::OptionTableName, "all-clients", Options::AllClients, 'C', 0, &MsgSupp::OptionAllClients, "size", Options::CheckSize, 's', 0, &MsgSupp::OptionCheckSize, "transfer", Options::Transfer, 't', 0, &MsgSupp::OptionTransfer, "update", Options::Update, 'u', 0, &MsgSupp::OptionUpdate, "verify", Options::Verify, 'v', 0, &MsgSupp::OptionVerify, "no-archive", Options::NoArchive, 'X', 0, &MsgSupp::OptionNoArchive, "serverid", Options::Serverid, 's', ':', &MsgSupp::OptionServerid, "unified", Options::Unified, 'u', 0, &MsgSupp::OptionUnified, "preview-noncontent", Options::PreviewNC, 'N', 0, &MsgSupp::OptionPreviewNC, "estimates", Options::Estimates, 'N', 0, &MsgSupp::OptionEstimates, "locked", Options::Locked, 'L', 0, &MsgSupp::OptionLocked, "unload-all", Options::UnloadAll, 'a', ':', &MsgSupp::OptionUnloadAll, "keep-have", Options::KeepHave, 'h', 0, &MsgSupp::OptionKeepHave, "yes", Options::Yes, 'y', 0, &MsgSupp::OptionYes, "no", Options::No, 'n', 0, &MsgSupp::OptionNo, "value", Options::InputValue, 'i', ':', &MsgSupp::OptionInputValue, "replacement", Options::Replacement, 'r', 0, &MsgSupp::OptionReplacement, "rebuild", Options::Rebuild, 'R', 0, &MsgSupp::OptionRebuild, "equal", Options::Equal, 'e', ':', &MsgSupp::OptionEqual, "attribute-pattern", Options::AttrPattern, 'A', ':', &MsgSupp::OptionAttrPattern, "diff-list-flag", Options::DiffListFlag, 's', ':', &MsgSupp::OptionDiffListFlag, "arguments", Options::Arguments, 'a', 0, &MsgSupp::OptionArguments, "environment", Options::Environment, 'e', 0, &MsgSupp::OptionEnvironment, "status", Options::TaskStatus, 's', ':', &MsgSupp::OptionTaskStatus, "all-users", Options::AllUsers, 'A', 0, &MsgSupp::OptionAllUsers, "promote", Options::Promote, 'p', 0, &MsgSupp::OptionPromote, "test", Options::Test, 't', ':', &MsgSupp::OptionTest, "active", Options::Active, 'A', 0, &MsgSupp::OptionActive, "groups", Options::GroupMode, 'g', 0, &MsgSupp::OptionGroupMode, "create", Options::Create, 'c', 0, &MsgSupp::OptionCreate, "list", Options::List, 'l', 0, &MsgSupp::OptionList, "mainline", Options::Mainline, 'm', 0, &MsgSupp::OptionMainline, "movechanges", Options::MoveChanges, 'r', 0, &MsgSupp::OptionMoveChanges, "replication-status", Options::ReplicationStatus, 'J', 0, &MsgSupp::OptionReplicationStatus, // Options below this line have no short-form equivalent: "no-rejournal", Options::NoRejournal, 0, 0, &MsgSupp::OptionNoRejournal, "from", Options::From, 0, ':', &MsgSupp::OptionFrom, "to", Options::To, 0, ':', &MsgSupp::OptionTo, "parallel", Options::Parallel, 0, ':', &MsgSupp::OptionParallel, "parallel", Options::ParallelSubmit, 0, ':', &MsgSupp::OptionParallelSubmit, "pid-file", Options::PidFile, 0, '?', &MsgSupp::OptionPidFile, "noretransfer", Options::NoRetransfer, 0, '#', &MsgSupp::OptionNoRetransfer, "forcenoretransfer", Options::ForceNoRetransfer, 0, 0, &MsgSupp::OptionForceNoRetransfer, "durable-only", Options::DurableOnly, 0, 0, &MsgSupp::OptionDurableOnly, "non-acknowledging", Options::NonAcknowledging, 0, 0, &MsgSupp::OptionNonAcknowledging, "bypass-exclusive-lock", Options::BypassExclusiveLock, 0, 0, &MsgSupp::OptionBypassExlusiveLock, "retain-lbr-revisions", Options::RetainLbrRevisions, 0, 0, &MsgSupp::OptionRetainLbrRevisions, 0, 0, 0, 0, 0 } ; void Options::Parse( int &argc, StrPtr *&argv, const char *opts, int flag, const ErrorId &usage, Error *e ) { int longOpts[] = { 0 }; ParseLong( argc, argv, opts, longOpts, flag, usage, e ); } void Options::ParseLong( int &argc, StrPtr *&argv, const char *opts, const int *longOpts, int flag, const ErrorId &usage, Error *e ) { int explainMode = 0; for( ; argc; argc--, argv++ ) { char *arg; char *av = argv->Text(); if( av[0] != '-' || !av[1] ) break; if( av[1] == '-' ) { // Long-form option (--force, --change, --user, etc.) const char *opt_s = &av[2]; const char *opt_e = opt_s; StrBuf optName, optMsg; while( *opt_e && *opt_e != '=' ) opt_e++; optName.Set( opt_s, ( opt_e - opt_s ) ); optMsg << "-" << optName; if( !explainMode && optName == StrRef( "explain" ) ) { explainMode = 1; continue; } int i, l; int matches = 0; for( l = 0; longOpts[ l ]; l++ ) { for( i = 0; list[i].name; i++ ) { if( list[i].optionCode == longOpts[l] ) { matches = !strcmp( optName.Text(), list[i].name ); break; } } if( matches ) break; } if( !matches ) { e->Set( MsgSupp::Invalid ) << optMsg; goto usage; } if( explainMode ) { e->Set( usage ); e->Set( *list[i].help ); return; } if( optc == N_OPTS ) { e->Set( MsgSupp::TooMany ); return; } if( ! ( flags[ optc ] = list[i].shortForm ) ) flags[ optc ] = list[i].optionCode; flags2[ optc ] = 0; switch( list[i].valueType ) { default: if( *opt_e == '=' ) { e->Set( MsgSupp::ExtraArg ); goto usage; } vals[ optc++ ] = "true"; continue; case '?': if( *opt_e == '=' ) vals[ optc++ ] = &opt_e[1]; else vals[ optc++ ] = StrRef::Null(); break; case ':': case '#': // : is --option=value or --option value // # is --option=N or --option N, N >= 0 if( *opt_e == '=' ) { vals[ optc++ ] = &opt_e[1]; } else if( --argc ) { vals[ optc++ ] = *++argv; } else { e->Set( MsgSupp::NeedsArg ) << optMsg; goto usage; } if( list[i].valueType == '#' && (!vals[ optc - 1 ].IsNumeric() || vals[ optc - 1 ].Atoi64() < 0 ) ) { e->Set( MsgSupp::NeedsNonNegArg ) << optMsg; goto usage; } break; } continue; } // Short-form option (-c, -p, -i, etc.) for( arg = &av[1]; *arg; arg++ ) { const char *f; for( f = opts; *f; f++ ) if( *f == *arg ) break; if( !*f ) { e->Set( MsgSupp::Invalid ) << arg; goto usage; } if( explainMode ) { int i, l; int matches = 0; for( l = 0; longOpts[ l ]; l++ ) { for( i = 0; list[i].name; i++ ) { if( list[i].optionCode == longOpts[l] ) { if( matches = ( ( *f ) == list[i].shortForm ) ) break; } } if( matches ) break; } e->Set( usage ); if( matches ) e->Set( *list[i].help ); else if( longOpts[ 0 ] ) e->Set( MsgSupp::Invalid ) << arg; return; } if( optc == N_OPTS ) { e->Set( MsgSupp::TooMany ); return; } flags[ optc ] = *f; flags2[ optc ] = 0; switch( f[1] ) { default: // a : -a vals[ optc++ ] = "true"; continue; case '.': // a. : -avalue vals[ optc++ ] = &arg[1]; break; case '+': // a+ : -axvalue or -ax value if( !( flags2[ optc ] = *++arg ) ) { StrRef a( f, 1 ); e->Set( MsgSupp::Needs2Arg ) << a; goto usage; } // fall thru case ':': case '#': // a: : -avalue or -a value // a# : -aN or -a N, N >= 0 if( arg[1] ) { vals[ optc++ ] = &arg[1]; } else if( --argc ) { vals[ optc++ ] = *++argv; } else { StrRef a( f, 1 ); e->Set( MsgSupp::NeedsArg ) << a; goto usage; } if( f[1] == '#' && (!vals[ optc - 1 ].IsNumeric() || vals[ optc - 1 ].Atoi64() < 0 ) ) { StrRef a( f, 1 ); e->Set( MsgSupp::NeedsNonNegArg ) << a; goto usage; } } break; } } if( explainMode ) goto usage; if( argc == 0 && ( flag & OPT_NONE ) ) return; if( argc == 1 && ( flag & OPT_ONE ) ) return; if( argc == 2 && ( flag & OPT_TWO ) ) return; if( argc == 3 && ( flag & OPT_THREE ) ) return; if( argc > 3 && ( flag & OPT_MORE ) ) return; if( argc == 0 && ( flag & OPT_MAKEONE ) ) { argc = 1; argv = 0; return; } if( flag & OPT_NONE ) e->Set( MsgSupp::ExtraArg ); else e->Set( MsgSupp::WrongArg ); usage: e->Set( usage ); if( explainMode ) { for( int l = 0; longOpts[ l ]; l++ ) { for( int i = 0; list[i].name; i++ ) { if( list[i].optionCode == longOpts[l] ) { e->Set( *list[i].help ); break; } } } } } /* * Options::Parse() -- version for char **argv */ void Options::Parse( int &argc, char **&argv, const char *opts, int flag, const ErrorId &usage, Error *e ) { int longOpts[] = { 0 }; ParseLong( argc, argv, opts, longOpts, flag, usage, e ); } void Options::ParseLong( int &argc, char **&argv, const char *opts, const int *longOpts, int flag, const ErrorId &usage, Error *e ) { StrRef *sargv = new StrRef[ argc ]; StrPtr *s = sargv; for( int i = 0; i < argc; i++ ) sargv[ i ].Set( argv[i] ); ParseLong( argc, s, opts, longOpts, flag, usage, e ); argv += s - (StrPtr*)sargv; delete []sargv; } /* * Name: getoptval() - find an option given its character */ StrPtr * Options::GetValue( int opt, char flag2, int subopt ) { int i; for( i = 0; i < optc; i++ ) if( flags[i] == opt && flags2[i] == flag2 && !subopt-- ) return &vals[i]; return 0; } int Options::FormatOption( int i, Error *e ) { if( i >= 0 && i < optc ) { StrBuf f; f.Extend( (char)flags[i] ); StrBuf f2; if( flags2[i] ) f2.Extend( (char)flags2[i] ); e->Set( MsgSupp::OptionData ) << f << f2 << vals[i]; return 1; } return 0; } int Options::FormatOption( int i, StrBuf &f ) const { if( i >= 0 && i < optc ) { f.Extend( '-' ); f.Extend( (char)flags[i] ); if( flags2[i] ) f.Extend( (char)flags2[i] ); f.Extend( ' ' ); f.Append( &vals[i] ); return 1; } return 0; } int Options::HasOption( int i ) { return i >= 0 && i < optc; } void Options::GetOptionName( int i, StrBuf &sb ) { if( HasOption( i ) ) { sb.Clear(); sb.Extend( (char)flags[i] ); if( flags2[i] ) sb.Extend( (char)flags2[i] ); sb.Terminate(); } } void Options::GetOptionValue( int i, StrBuf &sb ) { if( HasOption( i ) ) sb.Set( vals[i] ); }