]> git.tdb.fi Git - libs/core.git/blob - source/core/getopt.cpp
Make sure all files have the correct header
[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 GetOpt::~GetOpt()
14 {
15         for(list<OptBase *>::iterator i=opts.begin(); i!=opts.end(); ++i)
16                 delete *i;
17 }
18
19 /**
20 Generates a single line that gives an overview about the known options.
21
22 @param   argv0  The program name to be used in the usage string
23
24 @return  The generated usage string
25 */
26 string GetOpt::generate_usage(const string &argv0) const
27 {
28         ostringstream line;
29         
30         line<<argv0;
31         for(list<OptBase *>::const_iterator i=opts.begin(); i!=opts.end(); ++i)
32         {
33                 line<<" [";
34                 if((*i)->get_short())
35                 {
36                         line<<'-'<<(*i)->get_short();
37                         if(!(*i)->get_long().empty())
38                                 line<<'|';
39                         else if((*i)->get_arg_type()==OPTIONAL_ARG)
40                                 line<<"[ARG]";
41                         else if((*i)->get_arg_type()==REQUIRED_ARG)
42                                 line<<" ARG";
43                 }
44                 if(!(*i)->get_long().empty())
45                 {
46                         line<<"--"<<(*i)->get_long();
47
48                         if((*i)->get_arg_type()==OPTIONAL_ARG)
49                                 line<<"[=ARG]";
50                         else if((*i)->get_arg_type()==REQUIRED_ARG)
51                                 line<<"=ARG";
52                 }
53                 line<<']';
54         }
55
56         return line.str();
57 }
58
59 /**
60 Generates help for known options in tabular format, one option per line.
61 The returned string will have a linefeed at the end.
62 */
63 string GetOpt::generate_help() const
64 {
65         string result;
66         for(list<OptBase *>::const_iterator i=opts.begin(); i!=opts.end(); ++i)
67         {
68                 ostringstream line;
69                 line<<"  ";
70                 if((*i)->get_short())
71                 {
72                         line<<'-'<<(*i)->get_short();
73                         if(!(*i)->get_long().empty())
74                                 line<<", ";
75                         else if((*i)->get_arg_type()==OPTIONAL_ARG)
76                                 line<<"[ARG]";
77                         else if((*i)->get_arg_type()==REQUIRED_ARG)
78                                 line<<" ARG";
79                 }
80                 if(!(*i)->get_long().empty())
81                 {
82                         line<<"--"<<(*i)->get_long();
83
84                         if((*i)->get_arg_type()==OPTIONAL_ARG)
85                                 line<<"[=ARG]";
86                         else if((*i)->get_arg_type()==REQUIRED_ARG)
87                                 line<<"=ARG";
88                 }
89
90                 line<<"  "<<(*i)->get_help()<<'\n';
91
92                 result+=line.str();
93         }
94         
95         return result;
96 }
97
98 void GetOpt::operator()(unsigned argc, const char *const *argv)
99 {
100         unsigned i=1;
101         for(; i<argc;)
102         {
103                 if(argv[i][0]=='-')
104                 {
105                         if(argv[i][1]=='-')
106                         {
107                                 if(!argv[i][2])
108                                         break;
109
110                                 i+=process_long(argv+i);
111                         }
112                         else
113                                 i+=process_short(argv+i);
114                 }
115                 else
116                         args.push_back(argv[i++]);
117         }
118         
119         for(; i<argc; ++i)
120                 args.push_back(argv[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