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