Subversion Repositories public

Rev

Rev 100 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
69 luk 1
 
2
/// application arguments processor implementation
3
/**
4
 * \file appargs.cpp
5
 *
6
 * application arguments processor
7
 *
108 luk 8
 * Copyright (C) 2007, 2008, 2012 Lukas Jelinek, <lukas@aiken.cz>
69 luk 9
 *
10
 * This program is free software; you can redistribute it and/or
11
 * modify it under the terms of one of the following licenses:
12
 *
13
 * \li 1. X11-style license (see LICENSE-X11)
14
 * \li 2. GNU Lesser General Public License, version 2.1 (see LICENSE-LGPL)
15
 * \li 3. GNU General Public License, version 2  (see LICENSE-GPL)
16
 *
17
 * If you want to help with choosing the best license for you,
18
 * please visit http://www.gnu.org/licenses/license-list.html.
19
 *
108 luk 20
 * Credits:
21
 *   Christian Ruppert (new include to build with GCC 4.4+)
22
 *
69 luk 23
 */
24
 
25
 
108 luk 26
#include <cstdio>
100 luk 27
#include <cstring>
28
 
69 luk 29
#include "strtok.h"
30
 
31
#include "appargs.h"
32
 
33
 
34
size_t AppArgs::s_minCnt = 0;
35
size_t AppArgs::s_maxCnt = APPARGS_NOLIMIT;
36
 
37
AA_LONG_MAP AppArgs::s_longMap;
38
AA_SHORT_MAP AppArgs::s_shortMap;
39
AA_VAL_LIST AppArgs::s_valList;
40
 
41
 
42
void AppArgs::Init(size_t valMinCnt, size_t valMaxCnt)
43
{
44
  s_minCnt = valMinCnt;
45
  s_maxCnt = valMaxCnt;
46
}
47
 
48
void AppArgs::Destroy()
49
{
50
  AA_LONG_MAP::iterator it = s_longMap.begin();
51
  while (it != s_longMap.end()) {
52
    delete (*it).second;
53
    it++;
54
  }
55
 
56
  s_longMap.clear();
57
  s_shortMap.clear();
58
  s_valList.clear();
59
}
60
 
61
void AppArgs::Parse(int argc, const char* const* argv)
62
{
63
  for (int i=1; i<argc; i++) {
64
    // this shouldn't occur
65
    if (argv[i] == NULL)
66
      return;
67
 
68
    if (IsOption(argv[i])) {
69
      if (IsLongOption(argv[i])) {
70
        std::string name, val;
71
        bool hasVal;
72
        if (ParseLong(argv[i], name, val, hasVal)) {
73
          AA_LONG_MAP::iterator it = s_longMap.find(name);
74
          if (it != s_longMap.end()) {
75
            AppArgOption_t* pOpt = (*it).second;
76
            pOpt->found = true;
77
            pOpt->hasVal = hasVal;
78
            pOpt->val = val;
79
          }
80
        }
81
      }
82
      else {
83
        char name;
84
        std::string val;
85
        bool hasVal;
86
        ParseShort(argv[i], name, val, hasVal);
87
        AA_SHORT_MAP::iterator it = s_shortMap.find(name);
88
        if (it != s_shortMap.end()) {
89
          AppArgOption_t* pOpt = (*it).second;
90
          pOpt->found = true;
91
          if (hasVal) {
92
            pOpt->hasVal = true;
93
            pOpt->val = val;
94
          }
95
          else {
96
            if (i+1 < argc && !IsOption(argv[i+1])) {
97
              pOpt->hasVal = true;
98
              pOpt->val = argv[i+1];
99
              i++;
100
            }
101
            else {
102
              pOpt->hasVal = false;
103
            }
104
          }
105
        }
106
      }
107
    }
108
    else {
109
      s_valList.push_back(argv[i]);
110
    }
111
  }
112
}
113
 
114
bool AppArgs::IsValid()
115
{
116
  size_t size = s_valList.size();
117
  if (size < s_minCnt || size > s_maxCnt)
118
    return false;
119
 
120
  AA_LONG_MAP::iterator it = s_longMap.begin();
121
  while (it != s_longMap.end()) {
122
    AppArgOption_t* pOpt = (*it).second;
123
    if (pOpt->mand && !(pOpt->found))
124
      return false;
125
    if (pOpt->type == AAT_MANDATORY_VALUE && pOpt->found && !(pOpt->hasVal))
126
      return false;
127
    it++;
128
  }
129
 
130
  return true;
131
}
132
 
133
bool AppArgs::ExistsOption(const std::string& rArg)
134
{
135
  AA_LONG_MAP::iterator it = s_longMap.find(rArg);
136
  return it != s_longMap.end() && (*it).second->found;
137
}
138
 
139
bool AppArgs::GetOption(const std::string& rArg, std::string& rVal)
140
{
141
  AA_LONG_MAP::iterator it = s_longMap.find(rArg);
142
  if (it == s_longMap.end())
143
    return false;
144
 
145
  AppArgOption_t* pOpt = (*it).second;
146
  if (!(pOpt->found) || !(pOpt->hasVal))
147
    return false;
148
 
149
  rVal = pOpt->val;
150
  return true;
151
}
152
 
153
bool AppArgs::AddOption(const std::string& rName, char cShort, AppArgType_t type, bool fMandatory)
154
{
155
  if (s_longMap.find(rName) != s_longMap.end() || s_shortMap.find(cShort) != s_shortMap.end())
156
    return false;
157
 
158
  AppArgOption_t* pOpt = new AppArgOption_t();
159
  pOpt->found = false;
160
  pOpt->hasVal = false;
161
  pOpt->mand = fMandatory;
162
  pOpt->type = type;
163
 
164
  s_longMap.insert(AA_LONG_MAP::value_type(rName, pOpt));
165
  s_shortMap.insert(AA_SHORT_MAP::value_type(cShort, pOpt));
166
  return true;
167
}
168
 
169
size_t AppArgs::GetValueCount()
170
{
171
  return s_valList.size();
172
}
173
 
174
bool AppArgs::GetValue(size_t index, std::string& rVal)
175
{
176
  if (index > s_valList.size())
177
    return false;
178
 
179
  rVal = s_valList[index];
180
  return true;
181
}
182
 
183
void AppArgs::Dump()
184
{
185
  fprintf(stderr, "Options:\n");
186
  AA_LONG_MAP::iterator it = s_longMap.begin();
187
  while (it != s_longMap.end()) {
188
    AppArgOption_t* pOpt = (*it).second;
189
    AA_SHORT_MAP::iterator it2 = s_shortMap.begin();
190
    while (it2 != s_shortMap.end()) {
191
      if ((*it2).second == pOpt) {
192
        DumpOption((*it).first, (*it2).first, pOpt);
193
      }
194
      it2++;
195
    }      
196
    it++;
197
  }
198
 
199
  fprintf(stderr, "Values:\n");
200
 
201
  AA_VAL_LIST::iterator it3 = s_valList.begin();
202
  while (it3 != s_valList.end()) {
203
    fprintf(stderr, "%s\n", (*it3).c_str());
204
    it3++;
205
  }  
206
}
207
 
208
 
209
 
210
bool AppArgs::IsOption(const char* pchStr)
211
{
212
  if (strlen(pchStr) < 2)
213
    return false;
214
 
215
  return pchStr[0] == '-';
216
}
217
 
218
bool AppArgs::IsLongOption(const char* pchStr)
219
{
220
  return pchStr[1] == '-';
221
}
222
 
223
bool AppArgs::ParseLong(const char* pchStr, std::string& rName, std::string& rVal, bool& rfHasVal)
224
{
225
  StringTokenizer tok(pchStr+2, '=');
226
  if (!tok.HasMoreTokens())
227
    return false;
228
 
229
  rName = tok.GetNextToken();
230
  if (!tok.HasMoreTokens()) {
231
    rfHasVal = false;
232
    return true;
233
  }
234
 
235
  rVal = tok.GetRemainder();
236
  rfHasVal = true;
237
  return true;
238
}
239
 
240
void AppArgs::ParseShort(const char* pchStr, char& rcName, std::string& rVal, bool& rfHasVal)
241
{
242
  rcName = pchStr[1];
243
  size_t len = strlen(pchStr);
244
  if (len == 2) {
245
    rfHasVal = false;
246
    return;
247
  }
248
 
249
  rVal = pchStr + 2;
250
  rfHasVal = true;  
251
}
252
 
253
void AppArgs::DumpOption(const std::string& rName, char cShort, AppArgOption_t* pOpt)
254
{
255
  const char* s;
256
  switch (pOpt->type) {
257
    case AAT_NO_VALUE: s = "no value";
258
      break;
259
    case AAT_OPTIONAL_VALUE: s = "optional value";
260
      break;
261
    case AAT_MANDATORY_VALUE: s = "mandatory value";
262
      break;
263
    default:;
264
      s = "unknown";
265
  }
266
 
267
  fprintf(stderr, "long='%s', short='%c', type='%s', found=%s, has_value=%s, value='%s'\n",
268
      rName.c_str(),
269
      cShort,
270
      s,
271
      pOpt->found ? "YES" : "NO",
272
      pOpt->hasVal ? "YES" : "NO",
273
      pOpt->val.c_str()
274
  );
275
}
276
 
277