options.cc #1

  • //
  • guest/
  • perforce_software/
  • p4/
  • support/
  • options.cc
  • View
  • Commits
  • Open Download .zip Download (29 KB)
/*
 * 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,
	"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::OptionOmitMoved,
	"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,
	"show-flags",         Options::ShowFlags,    's', ':',
	                      &MsgSupp::OptionShowFlags,
	"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,
	"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,

	// 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,

	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 ':':
		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] );
}
# Change User Description Committed
#2 12188 Matt Attaway Move 'main' p4 into a release specific directory in prep for new releases
#1 9129 Matt Attaway Initial commit of the 2014.1 p4/p4api source code