]> git.donarmstrong.com Git - lilypond.git/blob - flower/getopt-long.cc
release: 1.2.4
[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 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 ("-" + _f("%c",arg_value_ch_a_a_[array_index_i_][argument_index_i_]))
152               : String (arg_value_ch_a_a_[array_index_i_])));
153       break;
154     case E_ILLEGALARG:
155       str += _f ("invalid argument `%s\' to option `%s'",
156         optional_argument_ch_C_, found_option_l_->str ());
157     default:
158       assert (false);
159     }
160   *error_ostream_l_ << str << endl;
161   exit (2);
162 }
163
164 const Long_option_init *
165 Getopt_long::parseshort()
166 {
167   char c=arg_value_ch_a_a_[array_index_i_][argument_index_i_];
168   found_option_l_=0;
169   assert (c);
170
171   for (int i=0; i < table_len_i_; i++)
172     if (option_a_[i].shortname_ch_ == c)
173       {
174         found_option_l_  = option_a_+i;
175         break;
176       }
177
178   if (!found_option_l_)
179     {
180       report (E_UNKNOWNOPTION);
181       return 0;
182     }
183
184   argument_index_i_++;
185   if (!found_option_l_->take_arg_sz_)
186     {
187       optional_argument_ch_C_ = 0;
188       return found_option_l_;
189     }
190   optional_argument_ch_C_ = arg_value_ch_a_a_[array_index_i_] + argument_index_i_;
191
192   array_index_i_ ++;
193   argument_index_i_ = 0;
194
195   if (!optional_argument_ch_C_[0])
196     {
197       optional_argument_ch_C_ = arg_value_ch_a_a_[array_index_i_];
198       array_index_i_ ++;
199     }
200   if (!optional_argument_ch_C_)
201     {
202       report (E_ARGEXPECT);
203     }
204
205   return found_option_l_;
206 }
207
208 const Long_option_init *
209 Getopt_long::operator()()
210 {
211   if (!ok())
212     return 0;
213
214   next();
215   if (!ok ())
216     return 0;
217
218   if (argument_index_i_)
219     return parseshort();
220
221   const char * argument_C = arg_value_ch_a_a_[array_index_i_];
222
223   if (argument_C[0] != '-')
224     return 0;
225
226   if (argument_C[1] == '-') {// what to do with "command  --  bla"
227     if (argument_C[2])
228       return parselong();
229     else
230       return 0;
231   }
232   else
233     {
234       if (argument_C[ 1 ])
235         {
236           argument_index_i_ = 1;
237           return parseshort();
238         }
239       else
240         {
241           return 0;
242         }
243     }
244 }
245
246
247
248 Getopt_long::Getopt_long (int c, char  **v, Long_option_init *lo)
249 {
250   option_a_ = lo;
251   error_ostream_l_ = &cerr;
252   arg_value_ch_a_a_ = v;
253   argument_count_i_ = c;
254   array_index_i_ = 1;
255   argument_index_i_ = 0;
256
257   //    reached end of option table?
258   table_len_i_ =0;
259   for (int i = 0;  option_a_[i].longname_sz_ ||option_a_[i].shortname_ch_; i++)
260     table_len_i_ ++;
261
262 }
263
264 bool
265 Getopt_long::ok() const
266 {
267   return  array_index_i_ < argument_count_i_;
268 }
269
270 void
271 Getopt_long::next()
272 {
273   error_ = E_NOERROR;
274   while (array_index_i_ < argument_count_i_
275          && !arg_value_ch_a_a_[array_index_i_][argument_index_i_])
276     {
277       array_index_i_++;
278       argument_index_i_ = 0;
279     }
280 }
281
282 char const *
283 Getopt_long::current_arg()
284 {
285   if (array_index_i_ >= argument_count_i_)
286     return 0;
287   char const * a = arg_value_ch_a_a_[array_index_i_];
288   return a + argument_index_i_;
289 }
290
291 char const *
292 Getopt_long::get_next_arg()
293 {
294   char const * a = current_arg();
295   if (a)
296     {
297       array_index_i_ ++;
298       argument_index_i_= 0;
299     }
300   return a;
301 }
302
303
304 const int EXTRA_SPACES = 5;
305
306 String
307 Long_option_init::table_str (Long_option_init *l) 
308 {
309   String argstr = "ARG";
310   String tabstr = "";
311
312   int wid = 0;
313   for (int i=0; l[i].shortname_ch_ || l[i].longname_sz_; i++)
314     {
315       wid = wid >? l[i].str_for_help ().length_i ();
316     }
317
318   for (int i=0; l[i].shortname_ch_ || l[i].longname_sz_; i++)
319     {
320       String s  =  "  " + l[i].str_for_help ();
321       s += String_convert::char_str (' ', wid - s.length_i () + EXTRA_SPACES);
322
323       tabstr += s + gettext (l[i].help_sz_) + "\n";
324     }
325
326     
327   return tabstr;
328 }
329
330 int
331 Long_option_init::compare (Long_option_init const &a, Long_option_init const &b)
332 {
333   if (a.shortname_ch_ && b.shortname_ch_ && a.shortname_ch_- b.shortname_ch_)
334     return a.shortname_ch_ - b.shortname_ch_;
335
336   if (b.shortname_ch_ && a.longname_sz_)
337     {
338       char s[2] = {b.shortname_ch_, 0};
339       return strcmp (a.longname_sz_, s);
340     }
341   if (a.shortname_ch_ && b.longname_sz_)
342     {
343       char s[2] = {a.shortname_ch_, 0};
344       return strcmp (s, b.longname_sz_);
345     }
346   
347   return strcmp (a.longname_sz_, b.longname_sz_);
348 }