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