]> git.tdb.fi Git - libs/core.git/blob - source/core/getopt.cpp
Assimilate exceptions and RefPtr from mspmisc
[libs/core.git] / source / core / getopt.cpp
1 /* $Id$
2
3 This file is part of libmspcore
4 Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7 #include "getopt.h"
8
9 using namespace std;
10
11 namespace Msp {
12
13 /**
14 Generates a single line that gives an overview about the known options.
15
16 @param   argv0  The program name to be used in the usage string
17
18 @return  The generated usage string
19 */
20 string GetOpt::generate_usage(const string &argv0) const
21 {
22         ostringstream line;
23         
24         line<<argv0;
25         for(list<OptBase *>::const_iterator i=opts.begin(); i!=opts.end(); ++i)
26         {
27                 line<<" [";
28                 if((*i)->get_short())
29                 {
30                         line<<'-'<<(*i)->get_short();
31                         if(!(*i)->get_long().empty())
32                                 line<<'|';
33                         else if((*i)->get_arg_type()==OPTIONAL_ARG)
34                                 line<<"[ARG]";
35                         else if((*i)->get_arg_type()==REQUIRED_ARG)
36                                 line<<" ARG";
37                 }
38                 if(!(*i)->get_long().empty())
39                 {
40                         line<<"--"<<(*i)->get_long();
41
42                         if((*i)->get_arg_type()==OPTIONAL_ARG)
43                                 line<<"[=ARG]";
44                         else if((*i)->get_arg_type()==REQUIRED_ARG)
45                                 line<<"=ARG";
46                 }
47                 line<<']';
48         }
49
50         return line.str();
51 }
52
53 /**
54 Generates help for known options in tabular format, one option per line.
55 The returned string will have a linefeed at the end.
56 */
57 string GetOpt::generate_help() const
58 {
59         string result;
60         for(list<OptBase *>::const_iterator i=opts.begin(); i!=opts.end(); ++i)
61         {
62                 ostringstream line;
63                 line<<"  ";
64                 if((*i)->get_short())
65                 {
66                         line<<'-'<<(*i)->get_short();
67                         if(!(*i)->get_long().empty())
68                                 line<<", ";
69                         else if((*i)->get_arg_type()==OPTIONAL_ARG)
70                                 line<<"[ARG]";
71                         else if((*i)->get_arg_type()==REQUIRED_ARG)
72                                 line<<" ARG";
73                 }
74                 if(!(*i)->get_long().empty())
75                 {
76                         line<<"--"<<(*i)->get_long();
77
78                         if((*i)->get_arg_type()==OPTIONAL_ARG)
79                                 line<<"[=ARG]";
80                         else if((*i)->get_arg_type()==REQUIRED_ARG)
81                                 line<<"=ARG";
82                 }
83
84                 line<<"  "<<(*i)->get_help()<<'\n';
85
86                 result+=line.str();
87         }
88         
89         return result;
90 }
91
92 void GetOpt::operator()(unsigned argc, const char *const *argv)
93 {
94         unsigned i=1;
95         for(; i<argc;)
96         {
97                 if(argv[i][0]=='-')
98                 {
99                         if(argv[i][1]=='-')
100                         {
101                                 if(!argv[i][2])
102                                         break;
103
104                                 i+=process_long(argv+i);
105                         }
106                         else
107                                 i+=process_short(argv+i);
108                 }
109                 else
110                         args.push_back(argv[i++]);
111         }
112         
113         for(; i<argc; ++i)
114                 args.push_back(argv[i]);
115 }
116
117 GetOpt::~GetOpt()
118 {
119         for(list<OptBase *>::iterator i=opts.begin(); i!=opts.end(); ++i)
120                 delete *i;
121 }
122
123 GetOpt::OptBase &GetOpt::get_option(char s)
124 {
125         for(list<OptBase *>::iterator i=opts.begin(); i!=opts.end(); ++i)
126                 if((*i)->get_short()==s)
127                         return **i;
128         throw UsageError(string("Unknown option -")+s);
129 }
130
131 GetOpt::OptBase &GetOpt::get_option(const string &l)
132 {
133         for(list<OptBase *>::iterator i=opts.begin(); i!=opts.end(); ++i)
134                 if((*i)->get_long()==l)
135                         return **i;
136         throw UsageError(string("Unknown option --")+l);
137 }
138
139 /**
140 Processes the given argument as a long option.
141
142 @param   argp  Pointer to the argument
143
144 @return  The number of arguments eaten (1 or 2)
145 */
146 unsigned GetOpt::process_long(const char *const *argp)
147 {
148         // Skip the --
149         const char *arg=argp[0]+2;
150
151         // See if the argument contains an =
152         unsigned equals=0;
153         for(; arg[equals] && arg[equals]!='='; ++equals);
154         
155         OptBase &opt=get_option(string(arg, equals));
156         
157         if(arg[equals])
158                 // Process the part after the = as option argument
159                 opt.process(arg+equals+1);
160         else if(opt.get_arg_type()==REQUIRED_ARG)
161         {
162                 if(!argp[1])
163                         throw UsageError("Premature end of arguments");
164
165                 // Process the next argument as option argument
166                 opt.process(argp[1]);
167                 return 2;
168         }
169         else
170                 opt.process();
171         
172         return 1;
173 }
174
175 /**
176 Processes short options from the given argument.
177
178 @param   argp  Pointer to the argument
179
180 @return  The number of arguments eaten (1 or 2)
181 */
182 unsigned GetOpt::process_short(const char *const *argp)
183 {
184         // Skip the -
185         const char *arg=argp[0]+1;
186
187         // Loop through all characters in the argument
188         for(; *arg; ++arg)
189         {
190                 OptBase &opt=get_option(*arg);
191
192                 if(arg[1] && opt.get_arg_type()!=NO_ARG)
193                 {
194                         // Need an option argument and we have characters left - use them
195                         opt.process(arg+1);
196                         return 1;
197                 }
198                 else if(opt.get_arg_type()==REQUIRED_ARG)
199                 {
200                         if(!argp[1])
201                                 throw UsageError("Premature end of arguments");
202                         
203                         // Use the next argument as option argument
204                         opt.process(argp[1]);
205                         return 2;
206                 }
207                 else
208                         opt.process();
209         }
210
211         return 1;
212 }
213
214 } // namespace Msp