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