]> git.donarmstrong.com Git - lilypond.git/blob - flower/getopt-long.cc
* lily/program-option.cc: rename from scm-option.cc
[lilypond.git] / flower / getopt-long.cc
1 /*
2   process command line, GNU style.
3
4   this is Copyleft (c) 1996--2005 Han-Wen Nienhuys, <hanwen@cs.uu.nl>
5 */
6
7 #include "getopt-long.hh"
8
9 #include <cstring>
10 #include <cassert>
11 #include <cstdlib>
12
13 #include <iostream>
14
15 #include "config.hh"
16 #include "string-convert.hh"
17
18 #if !HAVE_GETTEXT
19 inline char *
20 gettext (char const *s)
21 {
22   return (char *)s;
23 }
24 #else
25 #include <libintl.h>
26 #endif
27
28 long
29 Getopt_long::get_argument_index ()
30 {
31   long l;
32   if (!optional_argument_str0_
33       || sscanf (optional_argument_str0_, "%ld", &l) != 1)
34     report (E_ILLEGALARG);
35
36   return l;
37 }
38
39 const Long_option_init *
40 Getopt_long::parselong ()
41 {
42   char const *optnm = arg_value_char_a_a_[array_index_] + 2;
43   assert (*optnm);
44
45   char const *endopt = strchr (optnm, '=');
46   int searchlen  = (endopt) ? endopt - optnm : strlen (optnm);
47
48   found_option_=0;
49   for (int i=0; i< table_len_; i++)
50     {
51       char const *ln = option_a_[i].longname_str0_;
52
53       if (ln && !strncmp (ln, optnm, searchlen))
54         {
55           found_option_ = option_a_+i;
56           break;
57         }
58     }
59
60   if (!found_option_)
61     {
62       report (E_UNKNOWNOPTION);
63       return 0;
64     }
65   array_index_++;
66   argument_index_ = 0;
67
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     {
206       report (E_ARGEXPECT);
207     }
208
209   return found_option_;
210 }
211
212 const Long_option_init *
213 Getopt_long::operator () ()
214 {
215   if (!ok ())
216     return 0;
217
218   next ();
219   if (!ok ())
220     return 0;
221
222   if (argument_index_)
223     return parseshort ();
224
225   const char *argument = arg_value_char_a_a_[array_index_];
226
227   if (argument[0] != '-')
228     return 0;
229
230   if (argument[1] == '-') {// what to do with "command  --  bla"
231     if (argument[2])
232       return parselong ();
233     else
234       return 0;
235   }
236   else
237     {
238       if (argument[ 1 ])
239         {
240           argument_index_ = 1;
241           return parseshort ();
242         }
243       else
244         {
245           return 0;
246         }
247     }
248 }
249
250 Getopt_long::Getopt_long (int c, char **v, Long_option_init *lo)
251 {
252   option_a_ = lo;
253   error_out_ = stderr;
254   arg_value_char_a_a_ = v;
255   argument_count_ = c;
256   array_index_ = 1;
257   argument_index_ = 0;
258
259   //    reached end of option table?
260   table_len_ = 0;
261   for (int i = 0; option_a_[i].longname_str0_ || option_a_[i].shortname_char_; i++)
262     table_len_++;
263 }
264
265 bool
266 Getopt_long::ok () const
267 {
268   return array_index_ < argument_count_;
269 }
270
271 void
272 Getopt_long::next ()
273 {
274   error_ = E_NOERROR;
275   while (array_index_ < argument_count_
276          && !arg_value_char_a_a_[array_index_][argument_index_])
277     {
278       array_index_++;
279       argument_index_ = 0;
280     }
281 }
282
283 char const *
284 Getopt_long::current_arg ()
285 {
286   if (array_index_ >= argument_count_)
287     return 0;
288   char const *a = arg_value_char_a_a_[array_index_];
289   return a + argument_index_;
290 }
291
292 char const *
293 Getopt_long::get_next_arg ()
294 {
295   char const *a = current_arg ();
296   if (a)
297     {
298       array_index_++;
299       argument_index_ = 0;
300     }
301   return a;
302 }
303
304 const int EXTRA_SPACES = 5;
305
306 String
307 Long_option_init::table_string (Long_option_init *l)
308 {
309   String tabstr = "";
310
311   int wid = 0;
312   for (int i = 0; l[i].shortname_char_ || l[i].longname_str0_; i++)
313     {
314       wid = max (wid, l[i].str_for_help ().length ());
315     }
316
317   for (int i = 0; l[i].shortname_char_ || l[i].longname_str0_; i++)
318     {
319       String s = "  " + l[i].str_for_help ();
320       s += String_convert::char_string (' ', wid - s.length () + EXTRA_SPACES);
321
322       String help_text (gettext (l[i].help_str0_));
323       help_text.substitute ("\n", "\n" + String_convert::char_string (' ', wid + EXTRA_SPACES + 2));
324       tabstr += s + help_text + "\n";
325     }
326
327   return tabstr;
328 }
329
330 int
331 Long_option_init::compare (Long_option_init const &a, Long_option_init const &b)
332 {
333   if (a.shortname_char_ && b.shortname_char_ && a.shortname_char_- b.shortname_char_)
334     return a.shortname_char_ - b.shortname_char_;
335
336   if (b.shortname_char_ && a.longname_str0_)
337     {
338       char s[2] = {b.shortname_char_, 0};
339       return strcmp (a.longname_str0_, s);
340     }
341   if (a.shortname_char_ && b.longname_str0_)
342     {
343       char s[2] = {a.shortname_char_, 0};
344       return strcmp (s, b.longname_str0_);
345     }
346
347   return strcmp (a.longname_str0_, b.longname_str0_);
348 }