1 /*
2   CommandLine.cpp
3 
4   This file is part of Charm, a task-based time tracking application.
5 
6   Copyright (C) 2008-2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
7 
8   Author: Mirko Boehm <mirko.boehm@kdab.com>
9 
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation, either version 2 of the License, or
13   (at your option) any later version.
14 
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19 
20   You should have received a copy of the GNU General Public License
21   along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23 
24 #include "CommandLine.h"
25 #include "Exceptions.h"
26 
27 #include <QObject>
28 #include <QString>
29 
30 extern "C" {
31 #include <getopt.h>
32 }
33 
34 #include <iostream>
35 
CommandLine(int argc,char ** argv)36 CommandLine::CommandLine(int argc, char **argv)
37     : m_mode(Mode_None)
38     , m_index()
39     , m_userid()
40 {
41     opterr = 0;
42     int ch;
43     while ((ch = getopt(argc, argv, "vhza:x:c:ri:u:m:")) != -1)
44     {
45         if (ch == '?') {
46             // unparsable argument
47             int option = optopt;
48             if (option == 'a') {
49                 throw UsageException(QObject::tr(
50                                          "Option -a requires a filename argument"));
51             }
52             if (option == 'i') {
53                 throw UsageException(QObject::tr(
54                                          "Option -i requires an index argument"));
55             }
56             if (option == 'x') {
57                 throw UsageException(QObject::tr(
58                                          "Option -x requires a filename argument"));
59             }
60             if (option == 'm')
61                 throw UsageException(QObject::tr("Option -m requires a user comment argument"));
62             if (isprint(option)) {
63                 throw UsageException(
64                           QObject::tr("Unknown option %1").arg(option));
65             } else {
66                 int code = static_cast<int>(option);
67                 throw UsageException(QObject::tr("Unknown character %1").arg(
68                                          code));
69             }
70         }
71 
72         switch (ch) {
73         case 'a':
74             if (m_mode != Mode_None) {
75                 QString msg = QObject::tr(
76                     "Multiple mode selections, please use only one");
77                 throw UsageException(msg);
78             }
79             // mode
80             m_filename = QString::fromLocal8Bit(optarg);
81             m_mode = Mode_AddTimesheet;
82             break;
83         case 'x':
84             if (m_mode != Mode_None) {
85                 QString msg = QObject::tr(
86                     "Multiple mode selections, please use only one");
87                 throw UsageException(msg);
88             }
89             // mode
90             m_exportFilename = QString::fromLocal8Bit(optarg);
91             m_mode = Mode_ExportProjectcodes;
92             break;
93         case 'c':
94             if (m_mode != Mode_None) {
95                 QString msg = QObject::tr(
96                     "Multiple mode selections, please use only one");
97                 throw UsageException(msg);
98             }
99             m_userName = QString::fromLocal8Bit(optarg);
100             m_mode = Mode_CheckOrCreateUser;
101             break;
102 
103         case 'r':         // remove
104             if (m_mode != Mode_None) {
105                 QString msg = QObject::tr(
106                     "Multiple mode selections, please use only one");
107                 throw UsageException(msg);
108             }
109             m_mode = Mode_RemoveTimesheet;
110             break;
111         case 'u':         // user id
112         {
113             if (m_userid != 0) {
114                 QString msg = QObject::tr(
115                     "Multiple user id selections, please use only one");
116                 throw UsageException(msg);
117             }
118 
119             QString arg = QString::fromLocal8Bit(optarg);
120             bool ok;
121             m_userid = arg.toInt(&ok);
122             if (!ok || m_userid < 1) {
123                 throw UsageException(
124                           QObject::tr(
125                               "Argument to option -u must be an integer user id larger than zero"));
126             }
127             break;
128         }
129         case 'i':
130         {
131             // index
132             if (m_index != 0) {
133                 QString msg = QObject::tr(
134                     "Multiple index selections, please use only one");
135                 throw UsageException(msg);
136             }
137 
138             QString arg = QString::fromLocal8Bit(optarg);
139             bool ok;
140             m_index = arg.toInt(&ok);
141             if (!ok || m_index < 1) {
142                 throw UsageException(
143                           QObject::tr(
144                               "Argument to option -i must be an integer index larger than zero"));
145             }
146             break;
147         }
148         case 'm':
149         {
150             if (!m_userComment.isEmpty()) {
151                 QString msg = QObject::tr("Multiple user comments specified, please use only one");
152                 throw UsageException(msg);
153             }
154             QString arg = QString::fromLocal8Bit(optarg);
155             m_userComment = arg;
156             break;
157         }
158         case 'z':
159             // initialize the database
160             m_mode = Mode_InitializeDatabase;
161             break;
162         case 'v':
163             m_mode = Mode_PrintVersion;
164             break;
165         case 'h':
166         default:
167             // help/usage
168             m_mode = Mode_DescribeUsage;
169             //return;
170         }
171     }
172 
173     // check for other command line arguments and yell at the user:
174     if (optind < argc) {
175         QString msg;
176         for (int index = optind; index < argc; index++) {
177             msg += QObject::tr("Unknown extra argument \"%1\"\n").arg(
178                 QString::fromLatin1(argv[index]));
179         }
180         throw UsageException(msg);
181     }
182 
183     // final checks:
184     QString msg;
185     if (m_mode == Mode_None) {
186         msg += QObject::tr("No mode selected. Use one of -a filename, -r.");
187     } else if (m_mode == Mode_RemoveTimesheet) {
188         if (m_index < 1) {
189             msg += QObject::tr("No index specified. -a filename, "
190                                " -r require an index specified with -i.");
191         }
192 
193         if (m_userid < 1) {
194             msg += QObject::tr("No userid specified. -a filename, "
195                                " -r require a user id specified with -u.");
196         }
197     } else if (m_mode == Mode_AddTimesheet) {
198         if (m_index > 0)
199             msg += QObject::tr(
200                 "Specifying an index when adding a time sheet is not supported anymore.");
201     }
202 
203     if (!msg.isEmpty())
204         throw UsageException(msg);
205 }
206 
CommandLine(const QString file,const int userId)207 CommandLine::CommandLine(const QString file, const int userId)
208 {
209     m_filename = file;
210     m_userid = userId;
211 }
212 
CommandLine(const int userId,const int index)213 CommandLine::CommandLine(const int userId, const int index)
214 {
215     m_userid = userId;
216     m_index = index;
217 }
218 
mode() const219 CommandLine::Mode CommandLine::mode() const
220 {
221     return m_mode;
222 }
223 
userName() const224 QString CommandLine::userName() const
225 {
226     return m_userName;
227 }
228 
userComment() const229 QString CommandLine::userComment() const
230 {
231     return m_userComment;
232 }
233 
filename() const234 QString CommandLine::filename() const
235 {
236     return m_filename;
237 }
238 
exportFilename() const239 QString CommandLine::exportFilename() const
240 {
241     return m_exportFilename;
242 }
243 
userid() const244 int CommandLine::userid() const
245 {
246     return m_userid;
247 }
248 
index() const249 int CommandLine::index() const
250 {
251     return m_index;
252 }
253 
usage()254 void CommandLine::usage()
255 {
256     using namespace std;
257     cout << "Timesheet Processor, (C) 2008 Mirko Boehm, KDAB" << endl
258          << "Usage: " << endl
259          << "   * TimesheetProzessor -h                                         <-- get help"
260          << endl
261          << "   * TimesheetProzessor -v                                         <-- print version"
262          << endl
263          << "   * TimesheetProzessor -a filename -u userid -m comment  <-- add timesheet from file"
264          << endl
265          <<
266         "   * TimesheetProzessor -r -i index -u userid                      <-- remove timesheet at index"
267          << endl
268          <<
269         "   * TimesheetProzessor -c username                                <-- create user if user does not exist"
270          << endl
271          <<
272         "   * TimesheetProzessor -x filename                                <-- export project codes to XML file"
273          << endl
274          <<
275         "   * TimesheetProzessor -z                                         <-- initialize database (careful!)"
276          << endl;
277 }
278