-
Notifications
You must be signed in to change notification settings - Fork 0
/
printfun.cpp
154 lines (135 loc) · 4.16 KB
/
printfun.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <stdexcept>
#include "log.h"
#include "printfun.h"
namespace printfun {
std::map<std::string, printfun_t> printfuns;
static const char *parse_get_fmt_pos(const char *printfun_def,
unsigned int *out, std::string &func)
{
size_t fmt_pos_len;
if (*printfun_def != '(') {
std::string err("Fmt-string argument position is unknown in function `");
throw std::logic_error(err + func + "'");
}
printfun_def++;
try {
*out = std::stoul(printfun_def, &fmt_pos_len, 10);
} catch(...) {
std::string err("Invalid format position in `");
throw std::logic_error(err + func + "' function");
}
if (fmt_pos_len == 0) {
std::string err("Failed to parse format position of `");
throw std::logic_error(err + func + "' function");
}
printfun_def += fmt_pos_len;
if (*printfun_def != ')') {
std::string err("Can't find closing brace for fmt-string position of `");
throw std::logic_error(err + func + "' function");
}
printfun_def++;
if (*printfun_def == '\0') {
std::string err("Unexpected line end after `");
throw std::logic_error(err + func + "' function");
}
return printfun_def;
}
static const char *parse_get_function(const char *printfun_def,
std::string *out)
{
while (ISBLANK(*printfun_def)) printfun_def++;
if (*printfun_def == '\0')
throw std::logic_error("No function name specified");
if (!ISALPHA(*printfun_def) && *printfun_def != '_') {
std::string err("Function name should start with character or underscore, not with: `");
err += *printfun_def++;
while (ISALPHA(*printfun_def) ||
ISDIGIT(*printfun_def) ||
*printfun_def == '_')
err += *printfun_def++;
throw std::logic_error(err + "'");
}
while (ISALPHA(*printfun_def) || ISDIGIT(*printfun_def) ||
*printfun_def == '_')
*out += *printfun_def++;
return printfun_def;
}
static const char *parse_get_specifier(const char *printfun_def,
std::string *out)
{
while (ISBLANK(*printfun_def)) printfun_def++;
if (*printfun_def == '\0')
return printfun_def;
if (*printfun_def != '%') {
std::string err("Expected %-specifier, but got: `");
while (*printfun_def != '\0' && !ISBLANK(*printfun_def))
err += *printfun_def++;
throw std::logic_error(err + "'");
}
printfun_def++;
if (ISBLANK(*printfun_def))
throw std::logic_error("Got empty %-specifier");
while (!ISBLANK(*printfun_def)) {
if (*printfun_def == '\0') {
std::string err("Unexpected %-specifier end, got: `");
err += "%";
throw std::logic_error(err + *out + "'");
}
*out += *printfun_def++;
}
return printfun_def;
}
void add_printfun(const char *printfun_def)
{
printfun_t pf;
std::string fun_name;
unsigned int i;
printfun_def = parse_get_function(printfun_def, &fun_name);
printfun_def = parse_get_fmt_pos(printfun_def,
&pf.fmt_pos, fun_name);
printfun_def++; /* skip function delimiter */
for (i = 0;;i++) {
std::string spec, func;
printfun_def = parse_get_specifier(printfun_def, &spec);
if (*printfun_def == '\0')
break;
printfun_def = parse_get_function(printfun_def, &func);
printfun_def++; /* skip function delimiter */
if (pf.spec_to_func.find(spec) != pf.spec_to_func.end()) {
std::string err("%-Specifier `");
err += spec;
throw std::logic_error(err + "' found twice");
}
pf.spec_to_func[spec] = func;
if (spec[0] == '%') { /* it's %% specifier really */
if (spec.length() > 1) {
std::string err("Found `%");
err += spec;
err += "' specifier for `";
err += func;
err += "', can handle only `%%'";
throw std::logic_error(err);
}
log::info << "Reserved %% specifier for `"
<< func << "'\n";
}
}
if (i == 0) {
std::string err("Found no %-specifiers for `");
err += fun_name;
throw std::logic_error(err + "' function");
}
if (printfuns.find(fun_name) != printfuns.end()) {
std::string err("Function `");
err += fun_name;
throw std::logic_error(err + "' defined twice");
}
printfuns[fun_name] = pf;
log::info << "Specifier handlers for `"
<< fun_name << "(" << pf.fmt_pos << ")':\n";
std::map<std::string, std::string>::const_iterator s;
for (s = pf.spec_to_func.cbegin(); s != pf.spec_to_func.cend(); ++s)
log::debug << "\t%" << (*s).first
<< "\t" << (*s).second << std::endl;
}
}; /* namespace printfun */