]> git.donarmstrong.com Git - lilypond.git/blob - flower/getopt-long.cc
Revert "Issue 4550 (2/2) Avoid "using namespace std;" in included files"
[lilypond.git] / flower / getopt-long.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1996--2015 Han-Wen Nienhuys, <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "getopt-long.hh"
21
22 #include <cstring>
23 #include <cassert>
24 #include <cstdlib>
25
26 #include "config.hh"
27 #include "international.hh"
28
29 #if !HAVE_GETTEXT
30 inline char *
31 gettext (char const *s)
32 {
33   return (char *)s;
34 }
35 #else
36 #include <libintl.h>
37 #endif
38
39 using std::string;
40
41 long
42 Getopt_long::get_argument_index ()
43 {
44   long l;
45   if (!optional_argument_str0_
46       || sscanf (optional_argument_str0_, "%ld", &l) != 1)
47     report (E_ILLEGALARG);
48
49   return l;
50 }
51
52 const Long_option_init *
53 Getopt_long::parselong ()
54 {
55   char const *optnm = arg_value_char_a_a_[array_index_] + 2;
56   assert (*optnm);
57
58   char const *endopt = strchr (optnm, '=');
59   size_t searchlen = (endopt) ? (size_t) (endopt - optnm) : strlen (optnm);
60
61   found_option_ = 0;
62   for (int i = 0; i < table_len_; i++)
63     {
64       char const *ln = option_a_[i].longname_str0_;
65
66       if (ln && !strncmp (ln, optnm, searchlen))
67         {
68           found_option_ = option_a_ + i;
69           break;
70         }
71     }
72
73   if (!found_option_)
74     {
75       report (E_UNKNOWNOPTION);
76       return 0;
77     }
78   array_index_++;
79   argument_index_ = 0;
80
81   if (found_option_->take_arg_str0_)
82     {
83       if (endopt)
84         optional_argument_str0_ = endopt + 1; // a '='
85       else
86         {
87           optional_argument_str0_ = arg_value_char_a_a_[array_index_];
88           array_index_++;
89         }
90       if (!optional_argument_str0_)
91         report (E_ARGEXPECT);
92     }
93   else
94     {
95       optional_argument_str0_ = 0;
96       if (endopt)
97         report (E_NOARGEXPECT);
98     }
99
100   return found_option_;
101 }
102
103 string
104 Long_option_init::to_string () const
105 {
106   string str;
107   if (shortname_char_)
108     str += string ("-") + shortname_char_;
109   if (shortname_char_ && longname_str0_)
110     str += ", ";
111   if (longname_str0_)
112     str += string ("--") + longname_str0_;
113   return str;
114 }
115
116 string
117 Long_option_init::str_for_help () const
118 {
119   string s;
120   if (shortname_char_)
121     s = "-" + ::to_string (shortname_char_);
122   else
123     s = "  ";
124
125   s = s + ((shortname_char_ && longname_str0_) ? ", " : "  ");
126
127   if (longname_str0_)
128     s = s + "--" + longname_str0_;
129
130   if (take_arg_str0_)
131     {
132       if (longname_str0_)
133         s = s + "=";
134       else
135         s = s + " ";
136
137       s = s + gettext (take_arg_str0_);
138     }
139   return s;
140 }
141
142 // report an error, GNU style.
143 void
144 Getopt_long::report (Errorcod c)
145 {
146   error_ = c;
147   if (!error_out_)
148     return;
149
150   string str = arg_value_char_a_a_[0];
151   str += ": ";
152   switch (c)
153     {
154     case E_ARGEXPECT:
155       str += _f ("option `%s' requires an argument",
156                  found_option_->to_string ());
157       break;
158     case E_NOARGEXPECT:
159       str += _f ("option `%s' does not allow an argument",
160                  found_option_->to_string ());
161       break;
162     case E_UNKNOWNOPTION:
163       str += _f ("unrecognized option: `%s'",
164                  string (argument_index_
165                          ? string ("-" + string (1, arg_value_char_a_a_[array_index_][argument_index_]))
166                          : string (arg_value_char_a_a_[array_index_])));
167       break;
168     case E_ILLEGALARG:
169       str += _f ("invalid argument `%s' to option `%s'",
170                  optional_argument_str0_, found_option_->to_string ());
171       break;
172     default:
173       assert (false);
174     }
175   fprintf (error_out_, "%s\n", str.c_str ());
176   exit (2);
177 }
178
179 const Long_option_init *
180 Getopt_long::parseshort ()
181 {
182   char c = arg_value_char_a_a_[array_index_][argument_index_];
183   found_option_ = 0;
184   assert (c);
185
186   for (int i = 0; i < table_len_; i++)
187     if (option_a_[i].shortname_char_ == c)
188       {
189         found_option_ = option_a_ + i;
190         break;
191       }
192
193   if (!found_option_)
194     {
195       report (E_UNKNOWNOPTION);
196       return 0;
197     }
198
199   argument_index_++;
200   if (!found_option_->take_arg_str0_)
201     {
202       optional_argument_str0_ = 0;
203       return found_option_;
204     }
205   optional_argument_str0_ = arg_value_char_a_a_[array_index_] + argument_index_;
206
207   array_index_++;
208   argument_index_ = 0;
209
210   if (!optional_argument_str0_[0])
211     {
212       optional_argument_str0_ = arg_value_char_a_a_[array_index_];
213       array_index_++;
214     }
215   if (!optional_argument_str0_)
216     report (E_ARGEXPECT);
217
218   return found_option_;
219 }
220
221 const Long_option_init *
222 Getopt_long::operator () ()
223 {
224   if (!ok ())
225     return 0;
226
227   next ();
228   if (!ok ())
229     return 0;
230
231   if (argument_index_)
232     return parseshort ();
233
234   char const *argument = arg_value_char_a_a_[array_index_];
235
236   if (argument[0] != '-')
237     return 0;
238
239   if (argument[1] == '-')  // what to do with "command  --  bla"
240     {
241       if (argument[2])
242         return parselong ();
243       else
244         return 0;
245     }
246   else
247     {
248       if (argument[ 1 ])
249         {
250           argument_index_ = 1;
251           return parseshort ();
252         }
253       else
254         return 0;
255     }
256 }
257
258 Getopt_long::Getopt_long (int c, char **v, Long_option_init *lo)
259 {
260   option_a_ = lo;
261   error_out_ = stderr;
262   arg_value_char_a_a_ = v;
263   argument_count_ = c;
264   array_index_ = 1;
265   argument_index_ = 0;
266
267   //    reached end of option table?
268   table_len_ = 0;
269   for (int i = 0; option_a_[i].longname_str0_ || option_a_[i].shortname_char_; i++)
270     table_len_++;
271 }
272
273 bool
274 Getopt_long::ok () const
275 {
276   return array_index_ < argument_count_;
277 }
278
279 void
280 Getopt_long::next ()
281 {
282   error_ = E_NOERROR;
283   while (array_index_ < argument_count_
284          && !arg_value_char_a_a_[array_index_][argument_index_])
285     {
286       array_index_++;
287       argument_index_ = 0;
288     }
289 }
290
291 char const *
292 Getopt_long::current_arg ()
293 {
294   if (array_index_ >= argument_count_)
295     return 0;
296   char const *a = arg_value_char_a_a_[array_index_];
297   return a + argument_index_;
298 }
299
300 char const *
301 Getopt_long::get_next_arg ()
302 {
303   char const *a = current_arg ();
304   if (a)
305     {
306       array_index_++;
307       argument_index_ = 0;
308     }
309   return a;
310 }
311
312 const int EXTRA_SPACES = 5;
313
314 string
315 Long_option_init::table_string (Long_option_init *l)
316 {
317   string tabstr = "";
318
319   size_t wid = 0;
320   for (int i = 0; l[i].shortname_char_ || l[i].longname_str0_; i++)
321     wid = max (wid, l[i].str_for_help ().length ());
322
323   for (int i = 0; l[i].shortname_char_ || l[i].longname_str0_; i++)
324     {
325       string s = "  " + l[i].str_for_help ();
326       s += string (wid - s.length () + EXTRA_SPACES, ' ');
327
328       string help_text (gettext (l[i].help_str0_));
329       replace_all (&help_text, "\n",
330                    "\n" + string (wid + EXTRA_SPACES + 2, ' '));
331       tabstr += s + help_text + "\n";
332     }
333
334   return tabstr;
335 }
336
337 int
338 Long_option_init::compare (Long_option_init const &a, Long_option_init const &b)
339 {
340   if (a.shortname_char_ && b.shortname_char_ && a.shortname_char_ - b.shortname_char_)
341     return a.shortname_char_ - b.shortname_char_;
342
343   if (b.shortname_char_ && a.longname_str0_)
344     {
345       char s[2] = {b.shortname_char_, 0};
346       return strcmp (a.longname_str0_, s);
347     }
348   if (a.shortname_char_ && b.longname_str0_)
349     {
350       char s[2] = {a.shortname_char_, 0};
351       return strcmp (s, b.longname_str0_);
352     }
353
354   return strcmp (a.longname_str0_, b.longname_str0_);
355 }