https://github.com/akkartik/mu/blob/main/linux/bootstrap/001help.cc
1
2
3
4 :(before "End Commandline Parsing")
5 if (argc <= 1 || is_equal(argv[1], "--help")) {
6
7
8 cerr << get(Help, "usage");
9 return 0;
10 }
11
12
13
14
15 char** arg = &argv[1];
16 while (argc > 1 && starts_with(*arg, "--")) {
17 if (false)
18 ;
19
20 else
21 cerr << "skipping unknown option " << *arg << '\n';
22 --argc; ++argv; ++arg;
23 }
24
25 if (is_equal(argv[1], "help")) {
26 if (argc == 2) {
27 cerr << "help on what?\n";
28 help_contents();
29 return 0;
30 }
31 string key(argv[2]);
32
33 if (contains_key(Help, key)) {
34 cerr << get(Help, key);
35 return 0;
36 }
37 else {
38 cerr << "No help found for '" << key << "'\n";
39 help_contents();
40 cerr << "Please check your command for typos.\n";
41 return 1;
42 }
43 }
44
45 :(code)
46 void help_contents() {
47 cerr << "Available top-level topics:\n";
48 cerr << " usage\n";
49
50 }
51
52 :(before "End Globals")
53 map<string, string> Help;
54 :(before "End Includes")
55 #include <map>
56 using std::map;
57 :(before "End One-time Setup")
58 init_help();
59 :(code)
60 void init_help() {
61 put(Help, "usage",
62 "bootstrap: the bootstrap translator for SubX.\n"
63 "This program also wraps some miscellaneous useful functionality:\n"
64 " - an x86 emulator: `bootstrap run`\n"
65 " - online help: `bootstrap help`\n"
66 "\n"
67 "== Ways to invoke bootstrap\n"
68 "- See this message:\n"
69 " bootstrap --help\n"
70 "- Convert a textual SubX program into a standard ELF binary that you can\n"
71 " run on your computer:\n"
72 " bootstrap translate input1.subx input2.subx ... -o <output ELF binary>\n"
73 "- Run a SubX binary using SubX itself (for better error messages):\n"
74 " bootstrap run <ELF binary>\n"
75 "- Run all bootstrap's unit tests:\n"
76 " bootstrap test\n"
77 "- Run a single unit test:\n"
78 " bootstrap test <test name>\n"
79 " e.g. bootstrap test test_copy_imm32_to_EAX\n"
80 "\n"
81 "== Debugging aids\n"
82 "- Add '--trace' to any of these commands to save a trace to disk at the end.\n"
83 " This can run out of memory for long-running commands.\n"
84 "- Add '--debug' to emit additional debug information during translation.\n"
85 " 'bootstrap --debug translate' will save metadata to disk that\n"
86 " 'bootstrap --trace run' uses to make traces more informative.\n"
87 "\n"
88 "Options starting with '--' must always come before any other arguments.\n"
89 "\n"
90 "To start learning how to write SubX programs, see Readme.md (particularly\n"
91 "the section on the x86 instruction set) and then run:\n"
92 " bootstrap help\n"
93 );
94
95 }
96
97 :(code)
98 bool is_equal(const char* s, const char* lit) {
99 size_t len = strlen(lit);
100 if (strlen(s) != len) return false;
101 return strncmp(s, lit, len) == 0;
102 }
103
104 bool starts_with(const string& s, const string& pat) {
105 string::const_iterator a=s.begin(), b=pat.begin();
106 for (; a!=s.end() && b!=pat.end(); ++a, ++b)
107 if (*a != *b) return false;
108 return b == pat.end();
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167 :(before "End Includes")
168 #define SIZE(X) (assert((X).size() < (1LL<<(sizeof(int)*8-2))), static_cast<int>((X).size()))
169
170
171
172
173 :(before "atexit(reset)")
174 initialize_signal_handlers();
175
176
177 :(code)
178
179 void initialize_signal_handlers() {
180 struct sigaction action;
181 bzero(&action, sizeof(action));
182 action.sa_sigaction = dump_and_exit;
183 sigemptyset(&action.sa_mask);
184 sigaction(SIGABRT, &action, NULL);
185 sigaction(SIGILL, &action, NULL);
186 }
187 void dump_and_exit(int sig, siginfo_t* , void* ) {
188 switch (sig) {
189 case SIGABRT:
190 #ifndef __APPLE__
191 cerr << "SIGABRT: might be an integer overflow if it wasn't an assert() failure\n";
192 _Exit(1);
193 #endif
194 break;
195 case SIGILL:
196 #ifdef __APPLE__
197 cerr << "SIGILL: most likely caused by integer overflow\n";
198 _Exit(1);
199 #endif
200 break;
201 default:
202 break;
203 }
204 }
205 :(before "End Includes")
206 #include <signal.h>
207
208
209 :(before "Globals")
210
211 template<typename T> typename T::mapped_type& get(T& map, typename T::key_type const& key) {
212 typename T::iterator iter(map.find(key));
213 if (iter == map.end()) {
214 cerr << "get couldn't find key '" << key << "'\n";
215 assert(iter != map.end());
216 }
217 return iter->second;
218 }
219 template<typename T> typename T::mapped_type const& get(const T& map, typename T::key_type const& key) {
220 typename T::const_iterator iter(map.find(key));
221 if (iter == map.end()) {
222 cerr << "get couldn't find key '" << key << "'\n";
223 assert(iter != map.end());
224 }
225 return iter->second;
226 }
227 template<typename T> typename T::mapped_type const& put(T& map, typename T::key_type const& key, typename T::mapped_type const& value) {
228 map[key] = value;
229 return map[key];
230 }
231 template<typename T> bool contains_key(T& map, typename T::key_type const& key) {
232 return map.find(key) != map.end();
233 }
234 template<typename T> typename T::mapped_type& get_or_insert(T& map, typename T::key_type const& key) {
235 return map[key];
236 }
237 template<typename T> typename T::mapped_type const& put_new(T& map, typename T::key_type const& key, typename T::mapped_type const& value) {
238 assert(map.find(key) == map.end());
239 map[key] = value;
240 return map[key];
241 }
242
243
244
245
246
247
248 :(code)
249 bool has_data(istream& in) {
250 return in && !in.eof();
251 }
252
253 :(before "End Includes")
254 #include <assert.h>
255
256 #include <iostream>
257 using std::istream;
258 using std::ostream;
259 using std::iostream;
260 using std::cin;
261 using std::cout;
262 using std::cerr;
263 #include <iomanip>
264
265 #include <string.h>
266 #include <string>
267 using std::string;
268
269 #include <algorithm>
270 using std::min;
271 using std::max;