Throw instead of exiting from the tile clipping and overzooming code

The code reachable from overzooming a tile no longer calls exit(). It
reports errors by throwing tippecanoe_error, and owns its FILE * and
json_pull * handles through RAII wrappers so that nothing leaks when an
error unwinds the stack.

New files:

* errors.hpp/errors.cpp: the tippecanoe_error exception class, plus
  throw_tippecanoe_error() and throw_perror() helpers.
* raii.hpp: unique_file and unique_json_pull, both std::unique_ptr
  aliases, for FILE * and json_pull *.

exit() becomes throw in clip.cpp, mvt.cpp, mvt.hpp, read_json.cpp,
evaluator.cpp, text.cpp, geometry.cpp, attribute.cpp, and
write_json.hpp. Each tool's main() is now a try/catch around an
inner_main(), so the command-line tools exit with the status they
always did.

Along the way this fixes a z_stream leaked when compress() failed, an
exit() that could run from json_writer's destructor during unwinding,
and an exit() in mvt_value's hash function.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuCSVGssWNUCpVEE8Yp5HT
This commit is contained in:
Claude
2026-08-07 18:46:09 +00:00
parent 734bba7c78
commit 85547150c2
19 changed files with 272 additions and 170 deletions
+14 -2
View File
@@ -365,7 +365,7 @@ void join_csv(json_object *j) {
vo->value.number.large_unsigned = 0;
vo->value.number.large_signed = 0;
} else {
abort();
throw_tippecanoe_error(EXIT_IMPOSSIBLE, "unexpected JSON attribute type %d", attr_type);
}
properties->value.object.keys[properties->value.object.length] = ko;
@@ -437,7 +437,7 @@ void usage(char **argv) {
exit(EXIT_ARGS);
}
int main(int argc, char **argv) {
int inner_main(int argc, char **argv) {
const char *csv = NULL;
strip_usage_headings(long_options, real_long_options);
@@ -520,3 +520,15 @@ int main(int argc, char **argv) {
return fail;
}
int main(int argc, char **argv) {
try {
return inner_main(argc, argv);
} catch (tippecanoe_error &e) {
fprintf(stderr, "%s\n", e.what());
return e.exit_code;
} catch (std::exception &e) {
fprintf(stderr, "Error: %s\n", e.what());
return EXIT_FAILURE;
}
}