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