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