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