]> git.donarmstrong.com Git - lilypond.git/blob - flower/getopt-long.cc
*** empty log message ***
[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
252
253 Getopt_long::Getopt_long (int c, char  **v, Long_option_init *lo)
254 {
255   option_a_ = lo;
256   error_out_ = stderr;
257   arg_value_char_a_a_ = v;
258   argument_count_ = c;
259   array_index_ = 1;
260   argument_index_ = 0;
261
262   //    reached end of option table?
263   table_len_ =0;
264   for (int i = 0;  option_a_[i].longname_str0_ ||option_a_[i].shortname_char_; i++)
265     table_len_ ++;
266
267 }
268
269 bool
270 Getopt_long::ok () const
271 {
272   return  array_index_ < argument_count_;
273 }
274
275 void
276 Getopt_long::next ()
277 {
278   error_ = E_NOERROR;
279   while (array_index_ < argument_count_
280          && !arg_value_char_a_a_[array_index_][argument_index_])
281     {
282       array_index_++;
283       argument_index_ = 0;
284     }
285 }
286
287 char const *
288 Getopt_long::current_arg ()
289 {
290   if (array_index_ >= argument_count_)
291     return 0;
292   char const * a = arg_value_char_a_a_[array_index_];
293   return a + argument_index_;
294 }
295
296 char const *
297 Getopt_long::get_next_arg ()
298 {
299   char const * a = current_arg ();
300   if (a)
301     {
302       array_index_ ++;
303       argument_index_= 0;
304     }
305   return a;
306 }
307
308
309 const int EXTRA_SPACES = 5;
310
311 String
312 Long_option_init::table_string (Long_option_init *l) 
313 {
314   String argstr = "ARG";
315   String tabstr = "";
316
317   int wid = 0;
318   for (int i=0; l[i].shortname_char_ || l[i].longname_str0_; i++)
319     {
320       wid = wid >? l[i].str_for_help ().length ();
321     }
322
323   for (int i=0; l[i].shortname_char_ || l[i].longname_str0_; i++)
324     {
325       String s  =  "  " + l[i].str_for_help ();
326       s += String_convert::char_string (' ', wid - s.length () + EXTRA_SPACES);
327
328       tabstr += s + gettext (l[i].help_str0_) + "\n";
329     }
330
331     
332   return tabstr;
333 }
334
335 int
336 Long_option_init::compare (Long_option_init const &a, Long_option_init const &b)
337 {
338   if (a.shortname_char_ && b.shortname_char_ && a.shortname_char_- b.shortname_char_)
339     return a.shortname_char_ - b.shortname_char_;
340
341   if (b.shortname_char_ && a.longname_str0_)
342     {
343       char s[2] = {b.shortname_char_, 0};
344       return strcmp (a.longname_str0_, s);
345     }
346   if (a.shortname_char_ && b.longname_str0_)
347     {
348       char s[2] = {a.shortname_char_, 0};
349       return strcmp (s, b.longname_str0_);
350     }
351   
352   return strcmp (a.longname_str0_, b.longname_str0_);
353 }