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