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