]> git.donarmstrong.com Git - lilypond.git/blob - flower/getopt-long.cc
* flower
[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     }
82   else
83     {
84       optional_argument_str0_ = 0;
85       if (endopt)
86         report (E_NOARGEXPECT);
87     }
88
89   return found_option_;
90 }
91
92 String
93 Long_option_init::to_string () const
94 {
95   String str;
96   if (shortname_char_)
97     str += "-" + shortname_char_;
98   if (shortname_char_ && longname_str0_)
99     str += ", ";
100   if (longname_str0_)
101     str += String ("`--") + longname_str0_ + "'";
102   return str;
103 }
104
105 String
106 Long_option_init::str_for_help () const
107 {
108   String s;
109   if (shortname_char_)
110     s = "-" + ::to_string (shortname_char_);
111   else
112     s = "  ";
113
114   s = s + ((shortname_char_ && longname_str0_) ? ", " : "  ");
115
116   if (longname_str0_)
117     s = s + "--" + longname_str0_;
118
119   if (take_arg_str0_)
120     {
121       if (longname_str0_)
122         s = s + "=";
123       else
124         s = s + " ";
125
126       s = s + gettext (take_arg_str0_);
127     }
128   return s;
129 }
130
131 // report an error, GNU style.
132 void
133 Getopt_long::report (Errorcod c)
134 {
135   error_ = c;
136   if (!error_out_)
137     return;
138
139   String str = arg_value_char_a_a_[0];
140   str += ": ";
141   switch (c)
142     {
143     case E_ARGEXPECT:
144       str += _f ("option `%s' requires an argument",
145                  found_option_->to_string ());
146       break;
147     case E_NOARGEXPECT:
148       str += _f ("option `%s' doesn't allow an argument",
149                  found_option_->to_string ());
150       break;
151     case E_UNKNOWNOPTION:
152       str += _f ("unrecognized option: `%s'",
153                  String (argument_index_
154                          ? String ("-" + String_convert::form_string ("%c",
155                                                                       arg_value_char_a_a_[array_index_][argument_index_]))
156                          : String (arg_value_char_a_a_[array_index_])));
157       break;
158     case E_ILLEGALARG:
159       str += _f ("invalid argument `%s' to option `%s'",
160                  optional_argument_str0_, found_option_->to_string ());
161       break;
162     default:
163       assert (false);
164     }
165   fprintf (error_out_, "%s\n", str.to_str0 ());
166   exit (2);
167 }
168
169 const Long_option_init *
170 Getopt_long::parseshort ()
171 {
172   char c = arg_value_char_a_a_[array_index_][argument_index_];
173   found_option_ = 0;
174   assert (c);
175
176   for (int i = 0; i < table_len_; i++)
177     if (option_a_[i].shortname_char_ == c)
178       {
179         found_option_ = option_a_ + i;
180         break;
181       }
182
183   if (!found_option_)
184     {
185       report (E_UNKNOWNOPTION);
186       return 0;
187     }
188
189   argument_index_++;
190   if (!found_option_->take_arg_str0_)
191     {
192       optional_argument_str0_ = 0;
193       return found_option_;
194     }
195   optional_argument_str0_ = arg_value_char_a_a_[array_index_] + argument_index_;
196
197   array_index_++;
198   argument_index_ = 0;
199
200   if (!optional_argument_str0_[0])
201     {
202       optional_argument_str0_ = arg_value_char_a_a_[array_index_];
203       array_index_++;
204     }
205   if (!optional_argument_str0_)
206     {
207       report (E_ARGEXPECT);
208     }
209
210   return found_option_;
211 }
212
213 const Long_option_init *
214 Getopt_long::operator() ()
215 {
216   if (!ok ())
217     return 0;
218
219   next ();
220   if (!ok ())
221     return 0;
222
223   if (argument_index_)
224     return parseshort ();
225
226   const char *argument = arg_value_char_a_a_[array_index_];
227
228   if (argument[0] != '-')
229     return 0;
230
231   if (argument[1] == '-') {// what to do with "command  --  bla"
232     if (argument[2])
233       return parselong ();
234     else
235       return 0;
236   }
237   else
238     {
239       if (argument[ 1 ])
240         {
241           argument_index_ = 1;
242           return parseshort ();
243         }
244       else
245         {
246           return 0;
247         }
248     }
249 }
250
251 Getopt_long::Getopt_long (int c, char **v, Long_option_init *lo)
252 {
253   option_a_ = lo;
254   error_out_ = stderr;
255   arg_value_char_a_a_ = v;
256   argument_count_ = c;
257   array_index_ = 1;
258   argument_index_ = 0;
259
260   //    reached end of option table?
261   table_len_ =0;
262   for (int i = 0; option_a_[i].longname_str0_ ||option_a_[i].shortname_char_; i++)
263     table_len_++;
264
265 }
266
267 bool
268 Getopt_long::ok () const
269 {
270   return array_index_ < argument_count_;
271 }
272
273 void
274 Getopt_long::next ()
275 {
276   error_ = E_NOERROR;
277   while (array_index_ < argument_count_
278          && !arg_value_char_a_a_[array_index_][argument_index_])
279     {
280       array_index_++;
281       argument_index_ = 0;
282     }
283 }
284
285 char const *
286 Getopt_long::current_arg ()
287 {
288   if (array_index_ >= argument_count_)
289     return 0;
290   char const *a = arg_value_char_a_a_[array_index_];
291   return a + argument_index_;
292 }
293
294 char const *
295 Getopt_long::get_next_arg ()
296 {
297   char const *a = current_arg ();
298   if (a)
299     {
300       array_index_++;
301       argument_index_= 0;
302     }
303   return a;
304 }
305
306 const int EXTRA_SPACES = 5;
307
308 String
309 Long_option_init::table_string (Long_option_init *l)
310 {
311   String argstr = "ARG";
312   String tabstr = "";
313
314   int wid = 0;
315   for (int i = 0; l[i].shortname_char_ || l[i].longname_str0_; i++)
316     {
317       wid = wid >? l[i].str_for_help ().length ();
318     }
319
320   for (int i = 0; l[i].shortname_char_ || l[i].longname_str0_; i++)
321     {
322       String s = "  " + l[i].str_for_help ();
323       s += String_convert::char_string (' ', wid - s.length () + EXTRA_SPACES);
324
325       tabstr += s + gettext (l[i].help_str0_) + "\n";
326     }
327
328   return tabstr;
329 }
330
331 int
332 Long_option_init::compare (Long_option_init const &a, Long_option_init const &b)
333 {
334   if (a.shortname_char_ && b.shortname_char_ && a.shortname_char_- b.shortname_char_)
335     return a.shortname_char_ - b.shortname_char_;
336
337   if (b.shortname_char_ && a.longname_str0_)
338     {
339       char s[2] = {b.shortname_char_, 0};
340       return strcmp (a.longname_str0_, s);
341     }
342   if (a.shortname_char_ && b.longname_str0_)
343     {
344       char s[2] = {a.shortname_char_, 0};
345       return strcmp (s, b.longname_str0_);
346     }
347
348   return strcmp (a.longname_str0_, b.longname_str0_);
349 }