]> git.donarmstrong.com Git - lilypond.git/blob - flower/getopt-long.cc
release: 1.3.19
[lilypond.git] / flower / getopt-long.cc
1 /*
2    process command line, GNU style.
3
4    this is (Copyleft) 1996, Han-Wen Nienhuys, <hanwen@cs.uu.nl>
5  */
6
7 #include <string.h>
8 #include <stdio.h>
9 #include <iostream.h>
10 #include <assert.h>
11 #include "config.h"
12 #include "getopt-long.hh"
13 #include "international.hh"
14 #include "string-convert.hh"
15
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::argument_to_i()
29 {
30   long l;
31   if (!optional_argument_ch_C_
32       || sscanf (optional_argument_ch_C_, "%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_ch_a_a_[array_index_i_] + 2 ;
42   assert (*optnm);
43
44   char const *endopt = strchr (optnm, '=');
45   int searchlen  = (endopt) ? endopt - optnm : strlen (optnm);
46
47   found_option_l_=0;
48   for (int i=0; i< table_len_i_; i++)
49     {
50       char const *ln = option_a_[i].longname_sz_;
51
52       if (ln && !strncmp (ln, optnm, searchlen))
53         {
54           found_option_l_ = option_a_+i;
55           break;
56         }
57     }
58
59   if (!found_option_l_)
60     {
61       report (E_UNKNOWNOPTION);
62       return 0;
63     }
64   array_index_i_++;
65   argument_index_i_ = 0;
66
67
68   if (found_option_l_->take_arg_sz_)
69     {
70       if (endopt)
71         optional_argument_ch_C_ = endopt +1; // a '='
72       else
73         {
74           optional_argument_ch_C_ = arg_value_ch_a_a_[array_index_i_];
75           array_index_i_++;
76         }
77       if (!optional_argument_ch_C_)
78         report (E_ARGEXPECT);
79
80     }
81   else
82     {
83       optional_argument_ch_C_ = 0;
84       if (endopt)
85         report (E_NOARGEXPECT);
86     }
87
88   return found_option_l_;
89 }
90
91 String
92 Long_option_init::str () const
93 {
94   String str;
95   if (shortname_ch_)
96     str +=  "-" + shortname_ch_;
97   if (shortname_ch_ && longname_sz_)
98     str += ", ";
99   if (longname_sz_)
100     str += String ("`--") + longname_sz_ + "'";
101   return str;
102 }
103
104 String
105 Long_option_init::str_for_help () const
106 {
107   String s;
108   if (shortname_ch_)
109     s = "-" + to_str (shortname_ch_);
110   else
111     s = "  ";
112
113   s = s + ((shortname_ch_ && longname_sz_) ? "," : " ");
114
115   if (longname_sz_)
116     s = s + "--" + longname_sz_;
117
118   if (take_arg_sz_)
119     {
120       if (longname_sz_)
121         s = s + "=";
122       else
123         s = s + " ";
124       
125       s = s + gettext (take_arg_sz_);
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_ostream_l_)
136     return;
137
138   String str = arg_value_ch_a_a_[0];
139   str += ": ";
140   switch (c)
141     {
142     case E_ARGEXPECT:
143       str += _f ("Option `%s' requires an argument",
144         found_option_l_->str ());
145       break;
146     case  E_NOARGEXPECT:
147       str += _f ("Option `%s' doesn't allow an argument",
148         found_option_l_->str ());
149       break;
150     case E_UNKNOWNOPTION:
151       str += _f ("unrecognized option: `%s'",
152       String (argument_index_i_ 
153               ? String ("-" + String_convert::form_str ("%c", 
154                 arg_value_ch_a_a_[array_index_i_][argument_index_i_]))
155               : String (arg_value_ch_a_a_[array_index_i_])));
156       break;
157     case E_ILLEGALARG:
158       str += _f ("invalid argument `%s' to option `%s'",
159         optional_argument_ch_C_, found_option_l_->str ());
160     default:
161       assert (false);
162     }
163   *error_ostream_l_ << str << endl;
164   exit (2);
165 }
166
167 const Long_option_init *
168 Getopt_long::parseshort()
169 {
170   char c=arg_value_ch_a_a_[array_index_i_][argument_index_i_];
171   found_option_l_=0;
172   assert (c);
173
174   for (int i=0; i < table_len_i_; i++)
175     if (option_a_[i].shortname_ch_ == c)
176       {
177         found_option_l_  = option_a_+i;
178         break;
179       }
180
181   if (!found_option_l_)
182     {
183       report (E_UNKNOWNOPTION);
184       return 0;
185     }
186
187   argument_index_i_++;
188   if (!found_option_l_->take_arg_sz_)
189     {
190       optional_argument_ch_C_ = 0;
191       return found_option_l_;
192     }
193   optional_argument_ch_C_ = arg_value_ch_a_a_[array_index_i_] + argument_index_i_;
194
195   array_index_i_ ++;
196   argument_index_i_ = 0;
197
198   if (!optional_argument_ch_C_[0])
199     {
200       optional_argument_ch_C_ = arg_value_ch_a_a_[array_index_i_];
201       array_index_i_ ++;
202     }
203   if (!optional_argument_ch_C_)
204     {
205       report (E_ARGEXPECT);
206     }
207
208   return found_option_l_;
209 }
210
211 const Long_option_init *
212 Getopt_long::operator()()
213 {
214   if (!ok())
215     return 0;
216
217   next();
218   if (!ok ())
219     return 0;
220
221   if (argument_index_i_)
222     return parseshort();
223
224   const char * argument_C = arg_value_ch_a_a_[array_index_i_];
225
226   if (argument_C[0] != '-')
227     return 0;
228
229   if (argument_C[1] == '-') {// what to do with "command  --  bla"
230     if (argument_C[2])
231       return parselong();
232     else
233       return 0;
234   }
235   else
236     {
237       if (argument_C[ 1 ])
238         {
239           argument_index_i_ = 1;
240           return parseshort();
241         }
242       else
243         {
244           return 0;
245         }
246     }
247 }
248
249
250
251 Getopt_long::Getopt_long (int c, char  **v, Long_option_init *lo)
252 {
253   option_a_ = lo;
254   error_ostream_l_ = &cerr;
255   arg_value_ch_a_a_ = v;
256   argument_count_i_ = c;
257   array_index_i_ = 1;
258   argument_index_i_ = 0;
259
260   //    reached end of option table?
261   table_len_i_ =0;
262   for (int i = 0;  option_a_[i].longname_sz_ ||option_a_[i].shortname_ch_; i++)
263     table_len_i_ ++;
264
265 }
266
267 bool
268 Getopt_long::ok() const
269 {
270   return  array_index_i_ < argument_count_i_;
271 }
272
273 void
274 Getopt_long::next()
275 {
276   error_ = E_NOERROR;
277   while (array_index_i_ < argument_count_i_
278          && !arg_value_ch_a_a_[array_index_i_][argument_index_i_])
279     {
280       array_index_i_++;
281       argument_index_i_ = 0;
282     }
283 }
284
285 char const *
286 Getopt_long::current_arg()
287 {
288   if (array_index_i_ >= argument_count_i_)
289     return 0;
290   char const * a = arg_value_ch_a_a_[array_index_i_];
291   return a + argument_index_i_;
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_i_ ++;
301       argument_index_i_= 0;
302     }
303   return a;
304 }
305
306
307 const int EXTRA_SPACES = 5;
308
309 String
310 Long_option_init::table_str (Long_option_init *l) 
311 {
312   String argstr = "ARG";
313   String tabstr = "";
314
315   int wid = 0;
316   for (int i=0; l[i].shortname_ch_ || l[i].longname_sz_; i++)
317     {
318       wid = wid >? l[i].str_for_help ().length_i ();
319     }
320
321   for (int i=0; l[i].shortname_ch_ || l[i].longname_sz_; i++)
322     {
323       String s  =  "  " + l[i].str_for_help ();
324       s += String_convert::char_str (' ', wid - s.length_i () + EXTRA_SPACES);
325
326       tabstr += s + gettext (l[i].help_sz_) + "\n";
327     }
328
329     
330   return tabstr;
331 }
332
333 int
334 Long_option_init::compare (Long_option_init const &a, Long_option_init const &b)
335 {
336   if (a.shortname_ch_ && b.shortname_ch_ && a.shortname_ch_- b.shortname_ch_)
337     return a.shortname_ch_ - b.shortname_ch_;
338
339   if (b.shortname_ch_ && a.longname_sz_)
340     {
341       char s[2] = {b.shortname_ch_, 0};
342       return strcmp (a.longname_sz_, s);
343     }
344   if (a.shortname_ch_ && b.longname_sz_)
345     {
346       char s[2] = {a.shortname_ch_, 0};
347       return strcmp (s, b.longname_sz_);
348     }
349   
350   return strcmp (a.longname_sz_, b.longname_sz_);
351 }