forked from KhronosGroup/KTX-Software
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathargparser.cpp
128 lines (112 loc) · 3.45 KB
/
argparser.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/* -*- tab-width: 4; -*- */
/* vi: set sw=2 ts=4 expandtab: */
/*
* Copyright 2017-2020 Mark Callow, www.edgewise-cosulting.com.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @internal
* @class argparser
* @~English
*
* @brief parse a command argument list.
*
* Can't use getopt_long because it declares argv as char* const*. We
* need const char* const* when we're parsing an embedded string. Also
* Windows C library does not have getopt_long.
*
* @author Mark Callow, www.edgewise-consulting.com.
*/
#include <assert.h>
#include "argparser.h"
/*
* Construct from a string of arguments.
*/
argvector::argvector(const _tstring& sArgs)
{
const _tstring sep(_T(" \t\n\r\v\f"));
size_t pos;
pos = sArgs.find_first_not_of(sep);
assert(pos != _tstring::npos);
do {
size_t epos = sArgs.find_first_of(sep, pos);
size_t len = epos == _tstring::npos ? epos : epos - pos;
push_back(sArgs.substr(pos, len));
pos = sArgs.find_first_not_of(sep, epos);
} while (pos != _tstring::npos);
}
/*
* Construct from an array of C strings
*/
argvector::argvector(int argc, const _TCHAR* const* argv)
{
for (int i = 0; i < argc; i++) {
push_back(argv[i]);
}
}
/*
* Functions the same as getopt_long. See `man 3 getopt_long`.
*/
int
argparser::getopt(_tstring* shortopts, const struct option* longopts,
int* /*longindex*/)
{
if (optind == argv.size())
return -1;
_tstring arg;
arg = argv[optind];
if (arg[0] != _T('-') || (arg[0] == _T('-') && arg.size() == 1))
return -1;
optind++;
int retval = '?';
if (arg.compare(0, 2, _T("--")) == 0) {
if (arg.size() == 2) return -1; // " -- " separates options and files
const struct option* opt = longopts;
while (opt->name != nullptr) {
if (arg.compare(2, _tstring::npos, opt->name) == 0) {
retval = opt->val;
if (opt->has_arg != option::no_argument) {
if (optind >= argv.size() || (optarg = argv[optind++])[0] == '-') {
optarg.clear();
optind--;
if (opt->has_arg == option::required_argument)
retval = ':';
}
}
if (opt->flag != nullptr) {
*opt->flag = opt->val;
retval = 0;
}
break;
}
opt++;
}
} else if (shortopts != nullptr && arg.compare(0, 1, _T("-")) == 0) {
size_t pos = shortopts->find(arg.substr(1, 1));
if (pos != _tstring::npos) {
retval = (*shortopts)[pos];
if (pos < shortopts->length()
&& ((*shortopts)[++pos] == ':' || (*shortopts)[pos] == ';')) {
if (optind >= argv.size() || (optarg = argv[optind++])[0] == '-') {
optarg.clear();
optind--;
if ((*shortopts)[pos] == ':') // required argument
retval = ':';
}
}
}
}
return retval;
}
//================== Helper for apps' processArgs ========================
std::istream& operator >> (std::istream& stream, const skip& x)
{
std::ios_base::fmtflags f = stream.flags();
stream >> std::noskipws;
char c;
const _TCHAR* text = x.text;
while (stream && *text++)
stream >> c;
stream.flags(f);
return stream;
}