-
Notifications
You must be signed in to change notification settings - Fork 769
/
Copy pathsections.cpp
139 lines (119 loc) · 3.15 KB
/
sections.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
// Prints out section numbers, short names, and long names.
//
// Typical usage:
//
// cd draft/source/
// ../tools/sections std.tex > section_names.txt
//
#include <fstream>
#include <iostream>
#include <regex>
#include <sstream>
#include <string>
#include <vector>
class counter {
public:
counter()
: m_data{0}
, m_annex{false}
{
}
// Bump up the counter at the given depth.
//
// For example, 4.7.9 bumped at level 1 becomes 4.8, bumped at level 0 becomes 5.
void bump(int level)
{
m_data.resize(level + 1);
m_data.back()++;
}
// Start a new annex; resets the counter to 'A' the first time it's called,
// increments as if by bump(0) from there on.
void annex()
{
m_data.resize(1);
m_data.back() = m_annex ? m_data.back() + 1 : 0;
m_annex = true;
}
typedef std::vector<unsigned> data_t;
typedef data_t::const_iterator iterator;
iterator begin() const { return m_data.begin(); }
iterator end() const { return m_data.end(); }
bool is_annex() const { return m_annex; }
private:
data_t m_data;
bool m_annex;
};
std::ostream& operator<<(std::ostream& os, counter c)
{
bool first = true;
for (auto count : c) {
if (!first) {
os << '.';
}
if (first && c.is_annex()) {
os << static_cast<char>('A' + count);
} else {
os << count;
}
first = false;
}
return os;
}
void show(counter count, std::string shortname, std::string name)
{
std::cout << count << ": " << shortname << " - " << name << std::endl;
}
void process(std::string filename, counter& count)
{
std::cerr << "processing " << filename << std::endl;
std::ifstream file{filename};
if (!file) {
std::ostringstream os;
os << "Unable to open '" << filename << "' for processing";
throw std::runtime_error(os.str());
}
// We assume below that there is only one of these per source line.
// In the current draft, they're sometimes followed by comments, so
// we use regex_search() instead of regex_match() to be robust.
std::regex include{"^\\\\include\\{(.*)\\}"},
rSec{"^\\\\rSec([0-9])\\[(.*)\\]\\{(.*)\\}"},
annex{"^\\\\(inf|norm)annex\\{(.*)\\}\\{(.*)\\}"};
std::string line;
while (getline(file, line)) {
std::smatch results;
if (regex_search(line, results, include)) {
auto filename = results.str(1);
filename += ".tex";
process(filename, count);
} else if (regex_search(line, results, rSec)) {
auto level = results.str(1)[0] - '0';
auto shortname = results.str(2);
auto longname = results.str(3);
count.bump(level);
show(count, shortname, longname);
} else if (regex_search(line, results, annex)) {
auto shortname = results.str(2);
auto longname = results.str(3);
count.annex();
show(count, shortname, longname);
}
}
}
void process(std::string filename)
{
counter count;
process(filename, count);
}
int main(int argc, char** argv)
{
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " std.tex > output" << std::endl;
return 1;
}
try {
process(argv[1]);
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return 1;
}
}