-
Notifications
You must be signed in to change notification settings - Fork 2
/
arguments.cpp
108 lines (99 loc) · 3.56 KB
/
arguments.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
#include <arguments.h>
#include <util.h>
#include <cstring>
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdexcept>
struct print_usage : std::runtime_error {
print_usage() : runtime_error("pd - The Protodata Compiler\n"
"\n"
"Usage:\n"
"\n"
" pd (IN)*\n"
" ((-e|--eval) STRING)*\n"
" ((-o|--output) OUT)?\n"
" (-- (IN)*)?\n"
"\n"
"'pd' takes zero or more Protodata source files (IN), zero or\n"
"more Protodata strings to execute ('-e COMMAND'), and an\n"
"optional output file ('-o OUT'). It concatenates and\n"
"compiles all sources into one composite output. If no input\n"
"or output is specified, then source is read from standard\n"
"input or compiled to standard output, respectively.\n"
"\n"
"To read from standard input explicitly, use a hyphen ('-')\n"
"in place of a file path. To read from files whose names may\n"
"begin with dashes, precede them with a double dash ('--').\n"
"\n"
"'pd' reads lazily and writes eagerly. It returns 0 if all\n"
"input was consumed, or 1 if there was an error; the cause of\n"
"failure, if any, is printed on standard error.\n") {}
};
struct missing_value : std::runtime_error {
missing_value(const std::string& option)
: runtime_error(join("Missing value for option: '", option, "'.")) {}
};
struct excessive_value : std::runtime_error {
excessive_value(const std::string& option)
: runtime_error(join("Too many values for option: '", option, "'.")) {}
};
struct unknown_option : std::runtime_error {
unknown_option(const std::string& option)
: runtime_error(join("Unknown option: '", option, "'.")) {}
};
bool streq(const char* const a, const char* const b) {
return strcmp(a, b) == 0;
}
bool match_argument(const char* const argument,
const char* const short_name, const char* const long_name) {
return streq(argument, short_name) || streq(argument, long_name);
}
std::tuple<std::vector<Input>, unique_ostream>
parse_arguments(int count, const char* const* begin) {
using namespace std;
const char* const stdin_name = "STDIN";
--count;
++begin;
vector<Input> inputs;
unique_ostream output;
bool enable_parsing = true;
const auto end = begin + count;
for (auto argument = begin; argument != end; ++argument) {
if (!enable_parsing) {
inputs.push_back(Input(*argument,
unique_istream(new ifstream(*argument, ios::binary))));
continue;
}
if (match_argument(*argument, "-h", "--help")) {
throw print_usage();
} else if (match_argument(*argument, "-e", "--eval")) {
if (argument + 1 == end)
throw missing_value(*argument);
++argument;
inputs.push_back(Input(*argument,
unique_istream(new istringstream(*argument))));
} else if (match_argument(*argument, "-o", "--output")) {
if (output)
throw excessive_value(*argument);
if (argument + 1 == end)
throw missing_value(*argument);
++argument;
output.reset(new ofstream(*argument, ios::binary));
} else if (streq(*argument, "-")) {
inputs.push_back(Input(stdin_name, unique_istream(&cin)));
} else if (streq(*argument, "--")) {
enable_parsing = false;
} else if (**argument == '-') {
throw unknown_option(*argument);
} else {
inputs.push_back(Input(*argument,
unique_istream(new ifstream(*argument, ios::binary))));
}
}
if (inputs.empty())
inputs.push_back(Input(stdin_name, unique_istream(&cin)));
if (!output)
output.reset(&cout);
return make_tuple(move(inputs), move(output));
}