@@ -49,21 +49,21 @@ namespace boost { namespace program_options {
4949 }
5050
5151 option_description::
52- option_description (const char * name ,
52+ option_description (const char * names ,
5353 const value_semantic* s)
5454 : m_value_semantic(s)
5555 {
56- this ->set_name (name );
56+ this ->set_names (names );
5757 }
5858
5959
6060 option_description::
61- option_description (const char * name ,
61+ option_description (const char * names ,
6262 const value_semantic* s,
6363 const char * description)
6464 : m_description(description), m_value_semantic(s)
6565 {
66- this ->set_name (name );
66+ this ->set_names (names );
6767 }
6868
6969 option_description::~option_description ()
@@ -77,38 +77,42 @@ namespace boost { namespace program_options {
7777 bool short_ignore_case) const
7878 {
7979 match_result result = no_match;
80+ std::string local_option = (long_ignore_case ? tolower_ (option) : option);
8081
81- std::string local_long_name ((long_ignore_case ? tolower_ (m_long_name) : m_long_name));
82-
83- if (!local_long_name.empty ()) {
84-
85- std::string local_option = (long_ignore_case ? tolower_ (option) : option);
82+ for (std::vector<std::string>::const_iterator it (m_long_names.begin ()); it != m_long_names.end (); it++)
83+ {
84+ std::string local_long_name ((long_ignore_case ? tolower_ (*it) : *it));
8685
87- if (*local_long_name.rbegin () == ' *' )
88- {
89- // The name ends with '*'. Any specified name with the given
90- // prefix is OK.
91- if (local_option.find (local_long_name.substr (0 , local_long_name.length ()-1 ))
92- == 0 )
93- result = approximate_match;
94- }
86+ if (!local_long_name.empty ()) {
9587
96- if (local_long_name == local_option)
97- {
98- result = full_match;
99- }
100- else if (approx)
101- {
102- if (local_long_name.find (local_option) == 0 )
88+
89+ if ((result == no_match) && (*local_long_name.rbegin () == ' *' ))
90+ {
91+ // The name ends with '*'. Any specified name with the given
92+ // prefix is OK.
93+ if (local_option.find (local_long_name.substr (0 , local_long_name.length ()-1 ))
94+ == 0 )
95+ result = approximate_match;
96+ }
97+
98+ if (local_long_name == local_option)
99+ {
100+ result = full_match;
101+ break ;
102+ }
103+ else if (approx)
103104 {
104- result = approximate_match;
105+ if (local_long_name.find (local_option) == 0 )
106+ {
107+ result = approximate_match;
108+ }
105109 }
106110 }
111+
107112 }
108-
113+
109114 if (result != full_match)
110115 {
111- std::string local_option (short_ignore_case ? tolower_ (option) : option);
112116 std::string local_short_name (short_ignore_case ? tolower_ (m_short_name) : m_short_name);
113117
114118 if (local_short_name == local_option)
@@ -122,30 +126,35 @@ namespace boost { namespace program_options {
122126
123127 const std::string&
124128 option_description::key (const std::string& option) const
125- {
126- if (!m_long_name.empty ())
127- if (m_long_name.find (' *' ) != string::npos)
129+ {
130+ // We make the arbitrary choise of using the first long
131+ // name as the key, regardless of anything else
132+ if (!m_long_names.empty ()) {
133+ const std::string& first_long_name = *m_long_names.begin ();
134+ if (first_long_name.find (' *' ) != string::npos)
128135 // The '*' character means we're long_name
129136 // matches only part of the input. So, returning
130137 // long name will remove some of the information,
131138 // and we have to return the option as specified
132139 // in the source.
133140 return option;
134141 else
135- return m_long_name;
142+ return first_long_name;
143+ }
136144 else
137145 return m_short_name;
138146 }
139147
140148 std::string
141149 option_description::canonical_display_name (int prefix_style) const
142150 {
143- if (!m_long_name.empty ())
151+ // We prefer the first long name over any others
152+ if (!m_long_names.empty ())
144153 {
145154 if (prefix_style == command_line_style::allow_long)
146- return " --" + m_long_name ;
155+ return " --" + *m_long_names. begin () ;
147156 if (prefix_style == command_line_style::allow_long_disguise)
148- return " -" + m_long_name ;
157+ return " -" + *m_long_names. begin () ;
149158 }
150159 // sanity check: m_short_name[0] should be '-' or '/'
151160 if (m_short_name.length () == 2 )
@@ -155,8 +164,8 @@ namespace boost { namespace program_options {
155164 if (prefix_style == command_line_style::allow_dash_for_short)
156165 return string (" -" ) + m_short_name[1 ];
157166 }
158- if (!m_long_name .empty ())
159- return m_long_name ;
167+ if (!m_long_names .empty ())
168+ return *m_long_names. begin () ;
160169 else
161170 return m_short_name;
162171 }
@@ -165,21 +174,46 @@ namespace boost { namespace program_options {
165174 const std::string&
166175 option_description::long_name () const
167176 {
168- return m_long_name;
177+ static std::string empty_string (" " );
178+ return m_long_names.empty () ? empty_string : *m_long_names.begin ();
179+ }
180+
181+ const std::pair<const std::string*, std::size_t >
182+ option_description::long_names () const
183+ {
184+ return (m_long_names.empty ())
185+ ? std::pair<const std::string*, size_t >( NULL , 0 )
186+ : std::pair<const std::string*, size_t >( &(*m_long_names.begin ()), m_long_names.size ());
169187 }
170188
171189 option_description&
172- option_description::set_name (const char * _name )
190+ option_description::set_names (const char * _names )
173191 {
174- std::string name (_name);
175- string::size_type n = name.find (' ,' );
176- if (n != string::npos) {
177- assert (n == name.size ()-2 );
178- m_long_name = name.substr (0 , n);
179- m_short_name = ' -' + name.substr (n+1 ,1 );
180- } else {
181- m_long_name = name;
192+ m_long_names.clear ();
193+ std::istringstream iss (_names);
194+ std::string name;
195+
196+ while (std::getline (iss, name, ' ,' )) {
197+ m_long_names.push_back (name);
198+ }
199+ assert (!m_long_names.empty () && " No option names were specified" );
200+
201+ bool try_interpreting_last_name_as_a_switch = m_long_names.size () > 1 ;
202+ if (try_interpreting_last_name_as_a_switch) {
203+ const std::string& last_name = *m_long_names.rbegin ();
204+ if (last_name.length () == 1 ) {
205+ m_short_name = ' -' + last_name;
206+ m_long_names.pop_back ();
207+ // The following caters to the (valid) input of ",c" for some
208+ // character c, where the caller only wants this option to have
209+ // a short name.
210+ if (m_long_names.size () == 1 && (*m_long_names.begin ()).empty ()) {
211+ m_long_names.clear ();
212+ }
213+ }
182214 }
215+ // We could theoretically also ensure no remaining long names
216+ // are empty, or that none of them have length 1
183217 return *this ;
184218 }
185219
@@ -200,12 +234,12 @@ namespace boost { namespace program_options {
200234 {
201235 if (!m_short_name.empty ())
202236 {
203- return m_long_name .empty ()
237+ return m_long_names .empty ()
204238 ? m_short_name
205239 : string (m_short_name).append (" [ --" ).
206- append (m_long_name ).append (" ]" );
240+ append (*m_long_names. begin () ).append (" ]" );
207241 }
208- return string (" --" ).append (m_long_name );
242+ return string (" --" ).append (*m_long_names. begin () );
209243 }
210244
211245 std::string
0 commit comments