<commit_before>// for vasprintf() on Linux
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sqlite3.h>
#include <string>
#include <zlib.h>
#include <math.h>
#include "vector_tile.pb.h"
#include "tile.h"

extern "C" {
#include "projection.h"
#include "pool.h"
#include "mbtiles.h"
}

// https://github.com/mapbox/mapnik-vector-tile/blob/master/src/vector_tile_compression.hpp
inline bool is_compressed(std::string const &data) {
	return data.size() > 2 && (((uint8_t) data[0] == 0x78 && (uint8_t) data[1] == 0x9C) || ((uint8_t) data[0] == 0x1F && (uint8_t) data[1] == 0x8B));
}

// https://github.com/mapbox/mapnik-vector-tile/blob/master/src/vector_tile_compression.hpp
inline int decompress(std::string const &input, std::string &output) {
	z_stream inflate_s;
	inflate_s.zalloc = Z_NULL;
	inflate_s.zfree = Z_NULL;
	inflate_s.opaque = Z_NULL;
	inflate_s.avail_in = 0;
	inflate_s.next_in = Z_NULL;
	if (inflateInit2(&inflate_s, 32 + 15) != Z_OK) {
		fprintf(stderr, "error: %s\n", inflate_s.msg);
	}
	inflate_s.next_in = (Bytef *) input.data();
	inflate_s.avail_in = input.size();
	size_t length = 0;
	do {
		output.resize(length + 2 * input.size());
		inflate_s.avail_out = 2 * input.size();
		inflate_s.next_out = (Bytef *) (output.data() + length);
		int ret = inflate(&inflate_s, Z_FINISH);
		if (ret != Z_STREAM_END && ret != Z_OK && ret != Z_BUF_ERROR) {
			fprintf(stderr, "error: %s\n", inflate_s.msg);
			return 0;
		}

		length += (2 * input.size() - inflate_s.avail_out);
	} while (inflate_s.avail_out == 0);
	inflateEnd(&inflate_s);
	output.resize(length);
	return 1;
}

// https://github.com/mapbox/mapnik-vector-tile/blob/master/src/vector_tile_compression.hpp
static inline int compress(std::string const &input, std::string &output) {
	z_stream deflate_s;
	deflate_s.zalloc = Z_NULL;
	deflate_s.zfree = Z_NULL;
	deflate_s.opaque = Z_NULL;
	deflate_s.avail_in = 0;
	deflate_s.next_in = Z_NULL;
	deflateInit2(&deflate_s, Z_BEST_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
	deflate_s.next_in = (Bytef *) input.data();
	deflate_s.avail_in = input.size();
	size_t length = 0;
	do {
		size_t increase = input.size() / 2 + 1024;
		output.resize(length + increase);
		deflate_s.avail_out = increase;
		deflate_s.next_out = (Bytef *) (output.data() + length);
		int ret = deflate(&deflate_s, Z_FINISH);
		if (ret != Z_STREAM_END && ret != Z_OK && ret != Z_BUF_ERROR) {
			return -1;
		}
		length += (increase - deflate_s.avail_out);
	} while (deflate_s.avail_out == 0);
	deflateEnd(&deflate_s);
	output.resize(length);
	return 0;
}

void handle(std::string message, int z, unsigned x, unsigned y, struct pool **file_keys, char ***layernames, int *nlayers, sqlite3 *outdb) {
	GOOGLE_PROTOBUF_VERIFY_VERSION;

	// https://github.com/mapbox/mapnik-vector-tile/blob/master/examples/c%2B%2B/tileinfo.cpp
	mapnik::vector::tile tile;
	mapnik::vector::tile outtile;

	if (is_compressed(message)) {
		std::string uncompressed;
		decompress(message, uncompressed);
		if (!tile.ParseFromString(uncompressed)) {
			fprintf(stderr, "Couldn't decompress tile %d/%u/%u\n", z, x, y);
			exit(EXIT_FAILURE);
		}
	} else if (!tile.ParseFromString(message)) {
		fprintf(stderr, "Couldn't parse tile %d/%u/%u\n", z, x, y);
		exit(EXIT_FAILURE);
	}

	for (int l = 0; l < tile.layers_size(); l++) {
		mapnik::vector::tile_layer layer = tile.layers(l);
		mapnik::vector::tile_layer *outlayer = outtile.add_layers();

		outlayer->set_name(layer.name());
		outlayer->set_version(layer.version());
		outlayer->set_extent(layer.extent());

		const char *ln = layer.name().c_str();

		int ll;
		for (ll = 0; ll < *nlayers; ll++) {
			if (strcmp((*layernames)[ll], ln) == 0) {
				break;
			}
		}
		if (ll == *nlayers) {
			*file_keys = (struct pool *) realloc(*file_keys, (ll + 1) * sizeof(struct pool));
			*layernames = (char **) realloc(*layernames, (ll + 1) * sizeof(char *));

			if (*file_keys == NULL) {
				perror("realloc file_keys");
				exit(EXIT_FAILURE);
			}
			if (*layernames == NULL) {
				perror("realloc layernames");
				exit(EXIT_FAILURE);
			}

			pool_init(&((*file_keys)[ll]), 0);
			(*layernames)[ll] = strdup(ln);
			*nlayers = ll + 1;
		}

		struct pool keys, values;
		pool_init(&keys, 0);
		pool_init(&values, 0);

		for (int f = 0; f < layer.features_size(); f++) {
			mapnik::vector::tile_feature feat = layer.features(f);
			mapnik::vector::tile_feature *outfeature = outlayer->add_features();

			outfeature->set_type(feat.type());

			for (int g = 0; g < feat.geometry_size(); g++) {
				outfeature->add_geometry(feat.geometry(g));
			}

			for (int t = 0; t + 1 < feat.tags_size(); t += 2) {
				if (feat.tags(t) >= layer.keys_size() || feat.tags(t + 1) >= layer.values_size()) {
					printf("out of range: %d=%d\n", feat.tags(t), feat.tags(t + 1));
					continue;
				}

				const char *key = layer.keys(feat.tags(t)).c_str();
				mapnik::vector::tile_value const &val = layer.values(feat.tags(t + 1));
				char *value;
				int type;

				if (val.has_string_value()) {
					value = strdup(val.string_value().c_str());
					type = VT_STRING;
				} else if (val.has_int_value()) {
					asprintf(&value, "%lld", val.int_value());
					type = VT_NUMBER;
				} else if (val.has_double_value()) {
					asprintf(&value, "%g", val.double_value());
					type = VT_NUMBER;
				} else if (val.has_float_value()) {
					asprintf(&value, "%g", val.float_value());
					type = VT_NUMBER;
				} else if (val.has_bool_value()) {
					asprintf(&value, "%s", val.bool_value() ? "true" : "false");
					type = VT_BOOLEAN;
				} else if (val.has_sint_value()) {
					asprintf(&value, "%lld", val.sint_value());
					type = VT_NUMBER;
				} else if (val.has_uint_value()) {
					asprintf(&value, "%llu", val.uint_value());
					type = VT_NUMBER;
				} else {
					continue;
				}

				if (!is_pooled(&((*file_keys)[ll]), key, type)) {
					pool(&((*file_keys)[ll]), strdup(key), type);
				}

				struct pool_val *k, *v;

				if (is_pooled(&keys, key, VT_STRING)) {
					k = pool(&keys, key, VT_STRING);
				} else {
					k = pool(&keys, strdup(key), VT_STRING);
				}

				if (is_pooled(&values, value, type)) {
					v = pool(&values, value, type);
				} else {
					v = pool(&values, strdup(value), type);
				}

				outfeature->add_tags(k->n);
				outfeature->add_tags(v->n);
				free(value);
			}
		}

		struct pool_val *pv;
		for (pv = keys.head; pv != NULL; pv = pv->next) {
			outlayer->add_keys(pv->s, strlen(pv->s));
		}
		for (pv = values.head; pv != NULL; pv = pv->next) {
			mapnik::vector::tile_value *tv = outlayer->add_values();

			if (pv->type == VT_NUMBER) {
				tv->set_double_value(atof(pv->s));
			} else if (pv->type == VT_BOOLEAN) {
				tv->set_bool_value(pv->s[0] == 't');
			} else {
				tv->set_string_value(pv->s);
			}
		}

		pool_free_strings(&keys);
		pool_free_strings(&values);
	}

	std::string s;
	std::string compressed;

	outtile.SerializeToString(&s);
	compress(s, compressed);

	mbtiles_write_tile(outdb, z, x, y, compressed.data(), compressed.size());
}

void decode(char *fname, char *map, struct pool **file_keys, char ***layernames, int *nlayers, sqlite3 *outdb) {
	sqlite3 *db;

	if (sqlite3_open(fname, &db) != SQLITE_OK) {
		fprintf(stderr, "%s: %s\n", fname, sqlite3_errmsg(db));
		exit(EXIT_FAILURE);
	}

	const char *sql = "SELECT zoom_level, tile_column, tile_row, tile_data from tiles;";
	sqlite3_stmt *stmt;
	if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
		fprintf(stderr, "%s: select failed: %s\n", fname, sqlite3_errmsg(db));
		exit(EXIT_FAILURE);
	}

	while (sqlite3_step(stmt) == SQLITE_ROW) {
                long long zoom = sqlite3_column_int(stmt, 0);
                long long x = sqlite3_column_int(stmt, 1);
                long long y = sqlite3_column_int(stmt, 2);
                y = (1LL << zoom) - 1 - y;

		int len = sqlite3_column_bytes(stmt, 3);
		const char *s = (const char *) sqlite3_column_blob(stmt, 3);

		fprintf(stderr, "%lld/%lld/%lld   \r", zoom, x, y);

		handle(std::string(s, len), zoom, x, y, file_keys, layernames, nlayers, outdb);
	}

	sqlite3_finalize(stmt);

	if (sqlite3_close(db) != SQLITE_OK) {
		fprintf(stderr, "%s: could not close database: %s\n", fname, sqlite3_errmsg(db));
		exit(EXIT_FAILURE);
	}
}

void usage(char **argv) {
	fprintf(stderr, "Usage: %s [-f] [-c joins.csv] -o new.mbtiles source.mbtiles ...\n", argv[0]);
	exit(EXIT_FAILURE);
}

int main(int argc, char **argv) {
	char *outfile = NULL;
	char *csv = NULL;
	int force = 0;

	extern int optind;
	extern char *optarg;
	int i;

	while ((i = getopt(argc, argv, "fo:c:")) != -1) {
		switch (i) {
			case 'o':
				outfile = optarg;
				break;

			case 'f':
				force = 1;
				break;

			case 'c':
				csv = optarg;
				break;

			default:
				usage(argv);
		}
	}

	if (argc - optind < 1 || outfile == NULL) {
		usage(argv);
	}

	if (force) {
		unlink(outfile);
	}

	sqlite3 *outdb = mbtiles_open(outfile, argv);

	struct pool *file_keys = NULL;
	char **layernames = NULL;
	int nlayers = 0;

	for (i = optind; i < argc; i++) {
		decode(argv[i], csv, &file_keys, &layernames, &nlayers, outdb);
	}

	for (i = 0; i < nlayers; i++) {
		printf("%s\n", layernames[i]);
	}

	struct pool *fk[nlayers];
	for (i = 0; i < nlayers; i++) {
		fk[i] = &(file_keys[i]);
	}

	mbtiles_write_metadata(outdb, outfile, layernames, 0, 0, 0, 0, 0, 0, 0, 0, fk, nlayers);
	mbtiles_close(outdb, argv);

	return 0;
}
<commit_msg>Copy the bounding box, center, zoom range metadata over<commit_after>// for vasprintf() on Linux
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sqlite3.h>
#include <string>
#include <zlib.h>
#include <math.h>
#include "vector_tile.pb.h"
#include "tile.h"

extern "C" {
#include "projection.h"
#include "pool.h"
#include "mbtiles.h"
}

struct stats {
	int minzoom;
	int maxzoom;
	double midlat, midlon;
	double minlat, minlon, maxlat, maxlon;
};

// https://github.com/mapbox/mapnik-vector-tile/blob/master/src/vector_tile_compression.hpp
inline bool is_compressed(std::string const &data) {
	return data.size() > 2 && (((uint8_t) data[0] == 0x78 && (uint8_t) data[1] == 0x9C) || ((uint8_t) data[0] == 0x1F && (uint8_t) data[1] == 0x8B));
}

// https://github.com/mapbox/mapnik-vector-tile/blob/master/src/vector_tile_compression.hpp
inline int decompress(std::string const &input, std::string &output) {
	z_stream inflate_s;
	inflate_s.zalloc = Z_NULL;
	inflate_s.zfree = Z_NULL;
	inflate_s.opaque = Z_NULL;
	inflate_s.avail_in = 0;
	inflate_s.next_in = Z_NULL;
	if (inflateInit2(&inflate_s, 32 + 15) != Z_OK) {
		fprintf(stderr, "error: %s\n", inflate_s.msg);
	}
	inflate_s.next_in = (Bytef *) input.data();
	inflate_s.avail_in = input.size();
	size_t length = 0;
	do {
		output.resize(length + 2 * input.size());
		inflate_s.avail_out = 2 * input.size();
		inflate_s.next_out = (Bytef *) (output.data() + length);
		int ret = inflate(&inflate_s, Z_FINISH);
		if (ret != Z_STREAM_END && ret != Z_OK && ret != Z_BUF_ERROR) {
			fprintf(stderr, "error: %s\n", inflate_s.msg);
			return 0;
		}

		length += (2 * input.size() - inflate_s.avail_out);
	} while (inflate_s.avail_out == 0);
	inflateEnd(&inflate_s);
	output.resize(length);
	return 1;
}

// https://github.com/mapbox/mapnik-vector-tile/blob/master/src/vector_tile_compression.hpp
static inline int compress(std::string const &input, std::string &output) {
	z_stream deflate_s;
	deflate_s.zalloc = Z_NULL;
	deflate_s.zfree = Z_NULL;
	deflate_s.opaque = Z_NULL;
	deflate_s.avail_in = 0;
	deflate_s.next_in = Z_NULL;
	deflateInit2(&deflate_s, Z_BEST_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
	deflate_s.next_in = (Bytef *) input.data();
	deflate_s.avail_in = input.size();
	size_t length = 0;
	do {
		size_t increase = input.size() / 2 + 1024;
		output.resize(length + increase);
		deflate_s.avail_out = increase;
		deflate_s.next_out = (Bytef *) (output.data() + length);
		int ret = deflate(&deflate_s, Z_FINISH);
		if (ret != Z_STREAM_END && ret != Z_OK && ret != Z_BUF_ERROR) {
			return -1;
		}
		length += (increase - deflate_s.avail_out);
	} while (deflate_s.avail_out == 0);
	deflateEnd(&deflate_s);
	output.resize(length);
	return 0;
}

void handle(std::string message, int z, unsigned x, unsigned y, struct pool **file_keys, char ***layernames, int *nlayers, sqlite3 *outdb) {
	GOOGLE_PROTOBUF_VERIFY_VERSION;

	// https://github.com/mapbox/mapnik-vector-tile/blob/master/examples/c%2B%2B/tileinfo.cpp
	mapnik::vector::tile tile;
	mapnik::vector::tile outtile;

	if (is_compressed(message)) {
		std::string uncompressed;
		decompress(message, uncompressed);
		if (!tile.ParseFromString(uncompressed)) {
			fprintf(stderr, "Couldn't decompress tile %d/%u/%u\n", z, x, y);
			exit(EXIT_FAILURE);
		}
	} else if (!tile.ParseFromString(message)) {
		fprintf(stderr, "Couldn't parse tile %d/%u/%u\n", z, x, y);
		exit(EXIT_FAILURE);
	}

	for (int l = 0; l < tile.layers_size(); l++) {
		mapnik::vector::tile_layer layer = tile.layers(l);
		mapnik::vector::tile_layer *outlayer = outtile.add_layers();

		outlayer->set_name(layer.name());
		outlayer->set_version(layer.version());
		outlayer->set_extent(layer.extent());

		const char *ln = layer.name().c_str();

		int ll;
		for (ll = 0; ll < *nlayers; ll++) {
			if (strcmp((*layernames)[ll], ln) == 0) {
				break;
			}
		}
		if (ll == *nlayers) {
			*file_keys = (struct pool *) realloc(*file_keys, (ll + 1) * sizeof(struct pool));
			*layernames = (char **) realloc(*layernames, (ll + 1) * sizeof(char *));

			if (*file_keys == NULL) {
				perror("realloc file_keys");
				exit(EXIT_FAILURE);
			}
			if (*layernames == NULL) {
				perror("realloc layernames");
				exit(EXIT_FAILURE);
			}

			pool_init(&((*file_keys)[ll]), 0);
			(*layernames)[ll] = strdup(ln);
			*nlayers = ll + 1;
		}

		struct pool keys, values;
		pool_init(&keys, 0);
		pool_init(&values, 0);

		for (int f = 0; f < layer.features_size(); f++) {
			mapnik::vector::tile_feature feat = layer.features(f);
			mapnik::vector::tile_feature *outfeature = outlayer->add_features();

			outfeature->set_type(feat.type());

			for (int g = 0; g < feat.geometry_size(); g++) {
				outfeature->add_geometry(feat.geometry(g));
			}

			for (int t = 0; t + 1 < feat.tags_size(); t += 2) {
				if (feat.tags(t) >= layer.keys_size() || feat.tags(t + 1) >= layer.values_size()) {
					printf("out of range: %d=%d\n", feat.tags(t), feat.tags(t + 1));
					continue;
				}

				const char *key = layer.keys(feat.tags(t)).c_str();
				mapnik::vector::tile_value const &val = layer.values(feat.tags(t + 1));
				char *value;
				int type;

				if (val.has_string_value()) {
					value = strdup(val.string_value().c_str());
					type = VT_STRING;
				} else if (val.has_int_value()) {
					asprintf(&value, "%lld", val.int_value());
					type = VT_NUMBER;
				} else if (val.has_double_value()) {
					asprintf(&value, "%g", val.double_value());
					type = VT_NUMBER;
				} else if (val.has_float_value()) {
					asprintf(&value, "%g", val.float_value());
					type = VT_NUMBER;
				} else if (val.has_bool_value()) {
					asprintf(&value, "%s", val.bool_value() ? "true" : "false");
					type = VT_BOOLEAN;
				} else if (val.has_sint_value()) {
					asprintf(&value, "%lld", val.sint_value());
					type = VT_NUMBER;
				} else if (val.has_uint_value()) {
					asprintf(&value, "%llu", val.uint_value());
					type = VT_NUMBER;
				} else {
					continue;
				}

				if (!is_pooled(&((*file_keys)[ll]), key, type)) {
					pool(&((*file_keys)[ll]), strdup(key), type);
				}

				struct pool_val *k, *v;

				if (is_pooled(&keys, key, VT_STRING)) {
					k = pool(&keys, key, VT_STRING);
				} else {
					k = pool(&keys, strdup(key), VT_STRING);
				}

				if (is_pooled(&values, value, type)) {
					v = pool(&values, value, type);
				} else {
					v = pool(&values, strdup(value), type);
				}

				outfeature->add_tags(k->n);
				outfeature->add_tags(v->n);
				free(value);
			}
		}

		struct pool_val *pv;
		for (pv = keys.head; pv != NULL; pv = pv->next) {
			outlayer->add_keys(pv->s, strlen(pv->s));
		}
		for (pv = values.head; pv != NULL; pv = pv->next) {
			mapnik::vector::tile_value *tv = outlayer->add_values();

			if (pv->type == VT_NUMBER) {
				tv->set_double_value(atof(pv->s));
			} else if (pv->type == VT_BOOLEAN) {
				tv->set_bool_value(pv->s[0] == 't');
			} else {
				tv->set_string_value(pv->s);
			}
		}

		pool_free_strings(&keys);
		pool_free_strings(&values);
	}

	std::string s;
	std::string compressed;

	outtile.SerializeToString(&s);
	compress(s, compressed);

	mbtiles_write_tile(outdb, z, x, y, compressed.data(), compressed.size());
}

void decode(char *fname, char *map, struct pool **file_keys, char ***layernames, int *nlayers, sqlite3 *outdb, struct stats *st) {
	sqlite3 *db;

	if (sqlite3_open(fname, &db) != SQLITE_OK) {
		fprintf(stderr, "%s: %s\n", fname, sqlite3_errmsg(db));
		exit(EXIT_FAILURE);
	}

	const char *sql = "SELECT zoom_level, tile_column, tile_row, tile_data from tiles;";
	sqlite3_stmt *stmt;
	if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
		fprintf(stderr, "%s: select failed: %s\n", fname, sqlite3_errmsg(db));
		exit(EXIT_FAILURE);
	}

	while (sqlite3_step(stmt) == SQLITE_ROW) {
                long long zoom = sqlite3_column_int(stmt, 0);
                long long x = sqlite3_column_int(stmt, 1);
                long long y = sqlite3_column_int(stmt, 2);
                y = (1LL << zoom) - 1 - y;

		int len = sqlite3_column_bytes(stmt, 3);
		const char *s = (const char *) sqlite3_column_blob(stmt, 3);

		fprintf(stderr, "%lld/%lld/%lld   \r", zoom, x, y);

		handle(std::string(s, len), zoom, x, y, file_keys, layernames, nlayers, outdb);
	}

	sqlite3_finalize(stmt);

	if (sqlite3_prepare_v2(db, "SELECT value from metadata where name = 'minzoom'", -1, &stmt, NULL) == SQLITE_OK) {
		if (sqlite3_step(stmt) == SQLITE_ROW) {
			st->minzoom = sqlite3_column_int(stmt, 0);
		}
		sqlite3_finalize(stmt);
	}
	if (sqlite3_prepare_v2(db, "SELECT value from metadata where name = 'maxzoom'", -1, &stmt, NULL) == SQLITE_OK) {
		if (sqlite3_step(stmt) == SQLITE_ROW) {
			st->maxzoom = sqlite3_column_int(stmt, 0);
		}
		sqlite3_finalize(stmt);
	}
	if (sqlite3_prepare_v2(db, "SELECT value from metadata where name = 'center'", -1, &stmt, NULL) == SQLITE_OK) {
		if (sqlite3_step(stmt) == SQLITE_ROW) {
			const unsigned char *s = sqlite3_column_text(stmt, 0);
			sscanf((char *) s, "%lf,%lf", &st->midlon, &st->midlat);
		}
		sqlite3_finalize(stmt);
	}
	if (sqlite3_prepare_v2(db, "SELECT value from metadata where name = 'bounds'", -1, &stmt, NULL) == SQLITE_OK) {
		if (sqlite3_step(stmt) == SQLITE_ROW) {
			const unsigned char *s = sqlite3_column_text(stmt, 0);
			sscanf((char *) s, "%lf,%lf,%lf,%lf", &st->minlon, &st->minlat, &st->maxlon, &st->maxlat);
		}
		sqlite3_finalize(stmt);
	}

	if (sqlite3_close(db) != SQLITE_OK) {
		fprintf(stderr, "%s: could not close database: %s\n", fname, sqlite3_errmsg(db));
		exit(EXIT_FAILURE);
	}
}

void usage(char **argv) {
	fprintf(stderr, "Usage: %s [-f] [-c joins.csv] -o new.mbtiles source.mbtiles ...\n", argv[0]);
	exit(EXIT_FAILURE);
}

int main(int argc, char **argv) {
	char *outfile = NULL;
	char *csv = NULL;
	int force = 0;

	extern int optind;
	extern char *optarg;
	int i;

	while ((i = getopt(argc, argv, "fo:c:")) != -1) {
		switch (i) {
			case 'o':
				outfile = optarg;
				break;

			case 'f':
				force = 1;
				break;

			case 'c':
				csv = optarg;
				break;

			default:
				usage(argv);
		}
	}

	if (argc - optind < 1 || outfile == NULL) {
		usage(argv);
	}

	if (force) {
		unlink(outfile);
	}

	sqlite3 *outdb = mbtiles_open(outfile, argv);
	struct stats st;
	memset(&st, 0, sizeof(st));

	struct pool *file_keys = NULL;
	char **layernames = NULL;
	int nlayers = 0;

	for (i = optind; i < argc; i++) {
		decode(argv[i], csv, &file_keys, &layernames, &nlayers, outdb, &st);
	}

	for (i = 0; i < nlayers; i++) {
		printf("%s\n", layernames[i]);
	}

	struct pool *fk[nlayers];
	for (i = 0; i < nlayers; i++) {
		fk[i] = &(file_keys[i]);
	}

	mbtiles_write_metadata(outdb, outfile, layernames, st.minzoom, st.maxzoom, st.minlat, st.minlon, st.maxlat, st.maxlon, st.midlat, st.midlon, fk, nlayers);
	mbtiles_close(outdb, argv);

	return 0;
}
<|endoftext|>


<commit_before>//
// This file is part of Easylogging++ samples
//
// Demonstration of multithreaded application using pthread
//
// Compile this program using (if using gcc-c++ or intel or clang++):
//     [icpc | g++ | clang++] ./pthread.cpp -o bin/./pthread.cpp.bin -D_ELPP_THREAD_SAFE -std=c++0x -pthread -Wall -Wextra
//
// Revision: 1.1
// @author mkhan3189
//

#include <pthread.h>
#include "easylogging++.h"

_INITIALIZE_EASYLOGGINGPP

struct Args {
  const char* thrId;
  el::Logger* logger;
}args;

void* write2(void* args){
  struct Args* a = (struct Args*)args;

  char* threadId = (char*)a->thrId;
  el::Logger* logger = (el::Logger*)a->logger;
  CLOG(INFO, "default", "network") << "Triggering network log from default and network";

#if 1

  LOG(INFO) << "Writing from different function using macro [Thread #" << threadId << "]";

  logger->info("Info log from [Thread #%v]", threadId);
  logger->info("Info log");
  logger->verbose(2, "Verbose test [Thread #%v]", threadId);
  logger->verbose(2, "Verbose test");

  CLOG(INFO, "default", "network") << "Triggering network log from default and network";
#endif
  return NULL;
}

void *write(void* thrId){
  char* threadId = (char*)thrId;
  // Following line will be logged with every thread
  LOG(INFO) << "This standard log is written by [Thread #" << threadId << "]";
  // Following line will be logged with every thread only when --v=2 argument
  // is provided, i.e, ./bin/multithread_test.cpp.bin --v=2
  VLOG(2) << "This is verbose level 2 logging from [Thread #" << threadId << "]";

  // Following line will be logged only once from second running thread (which every runs second into
  // this line because of interval 2)
  LOG_EVERY_N(2, WARNING) << "This will be logged only once from thread who every reaches this line first. Currently running from [Thread #" << threadId << "]";

  for (int i = 1; i <= 10; ++i) {
     VLOG_IF(true, 2) << "Verbose condition [Thread #" << threadId << "]";
     VLOG_EVERY_N(2, 3) << "Verbose level 3 log every 4th time. This is at " << i << " from [Thread #" << threadId << "]";
  }

  // Following line will be logged once with every thread because of interval 1
  LOG_EVERY_N(1, INFO) << "This interval log will be logged with every thread, this one is from [Thread #" << threadId << "]";

  LOG_IF(strcmp(threadId, "2") == 0, INFO) << "This log is only for thread 2 and is ran by [Thread #" << threadId << "]";

  // Register 5 vague loggers
  for (int i = 1; i <= 5; ++i) {
     std::stringstream ss;
     ss << "logger" << i;
     el::Logger* logger = el::Loggers::getLogger(ss.str());
     LOG(INFO) << "Registered logger [" << ss.str() << "] [Thread #" << threadId << "]";
     CLOG(INFO, "default", "network") << "Triggering network log from default and network";
  }
  CLOG(INFO, "logger1") << "Logging using new logger [Thread #" << threadId << "]";
  CLOG(INFO, "no-logger") << "THIS SHOULD SAY LOGGER NOT REGISTERED YET [Thread #" << threadId << "]"; // << -- NOTE THIS!
  CLOG(INFO, "default", "network") << "Triggering network log from default and network";

  el::Logger* logger = el::Loggers::getLogger("default");
  logger->info("Info log from [Thread #%v]", threadId);

  // Check for log counters positions
  for (int i = 1; i <= 50; ++i) {
     LOG_EVERY_N(2, INFO) << "Counter pos: " << ELPP_COUNTER_POS << " [Thread #" << threadId << "]";
  }
  LOG_EVERY_N(2, INFO) << "Counter pos: " << ELPP_COUNTER_POS << " [Thread #" << threadId << "]";
  return NULL;
}

// If you wish you can define your own way to get thread ID
const char* getThreadId_CustomVersion(void) {
    return std::to_string(static_cast<long long>(pthread_self())).c_str();
}

int main(int argc, char** argv)
{
     _START_EASYLOGGINGPP(argc, argv);

     // Your thread ID specification
     el::CustomFormatSpecifier myThreadIdSpecifier("%mythreadId", getThreadId_CustomVersion);
     el::Helpers::installCustomFormatSpecifier(myThreadIdSpecifier);

     el::Loggers::addFlag(el::LoggingFlag::MultiLoggerSupport);

     // Note your %mythreadId or built-in, both are logged
     el::Loggers::reconfigureAllLoggers(el::ConfigurationType::Format, "%datetime %level (%thread | %mythreadId) [%logger] [%func] [%loc] %msg");
     el::Loggers::reconfigureAllLoggers(el::Level::Verbose, el::ConfigurationType::Format, "%datetime %level-%vlevel (%thread | %mythreadId) [%logger] [%func] [%loc] %msg");
     el::Loggers::getLogger("network");

     pthread_t thread1, thread2, thread3, thread4;

     // Create independent threads each of which will execute function
     pthread_create( &thread1, NULL, write, (void*)"1");
     pthread_create( &thread2, NULL, write, (void*)"2");
     pthread_create( &thread3, NULL, write, (void*)"3");

     el::Logger* logger = el::Loggers::getLogger("default");
     args.thrId = "4";
     args.logger = logger;
     pthread_create( &thread4, NULL, write2, (void*)&args);

     pthread_join(thread1, NULL);
     pthread_join(thread2, NULL);
     pthread_join(thread3, NULL);
     pthread_join(thread4, NULL);

    exit(0);
}
<commit_msg>updated to sample<commit_after>//
// This file is part of Easylogging++ samples
//
// Demonstration of multithreaded application using pthread
//
// Compile this program using (if using gcc-c++ or intel or clang++):
//     [icpc | g++ | clang++] ./pthread.cpp -o bin/./pthread.cpp.bin -D_ELPP_THREAD_SAFE -std=c++0x -pthread -Wall -Wextra
//
// Revision: 1.1
// @author mkhan3189
//

#include <pthread.h>
#include "easylogging++.h"

_INITIALIZE_EASYLOGGINGPP

struct Args {
  const char* thrId;
  el::Logger* logger;
}args;

void* write2(void* args){
  struct Args* a = (struct Args*)args;

  char* threadId = (char*)a->thrId;
  el::Logger* logger = (el::Logger*)a->logger;
  CLOG(INFO, "default", "network") << "Triggering network log from default and network";

  LOG(INFO) << "Writing from different function using macro [Thread #" << threadId << "]";

  logger->info("Info log from [Thread #%v]", threadId);
  logger->info("Info log");
  logger->verbose(2, "Verbose test [Thread #%v]", threadId);
  logger->verbose(2, "Verbose test");

  CLOG(INFO, "default", "network") << "Triggering network log from default and network";
  return NULL;
}

void *write(void* thrId){
  char* threadId = (char*)thrId;
  // Following line will be logged with every thread
  LOG(INFO) << "This standard log is written by [Thread #" << threadId << "]";
  // Following line will be logged with every thread only when --v=2 argument
  // is provided, i.e, ./bin/multithread_test.cpp.bin --v=2
  VLOG(2) << "This is verbose level 2 logging from [Thread #" << threadId << "]";

  // Following line will be logged only once from second running thread (which every runs second into
  // this line because of interval 2)
  LOG_EVERY_N(2, WARNING) << "This will be logged only once from thread who every reaches this line first. Currently running from [Thread #" << threadId << "]";

  for (int i = 1; i <= 10; ++i) {
     VLOG_IF(true, 2) << "Verbose condition [Thread #" << threadId << "]";
     VLOG_EVERY_N(2, 3) << "Verbose level 3 log every 4th time. This is at " << i << " from [Thread #" << threadId << "]";
  }

  // Following line will be logged once with every thread because of interval 1
  LOG_EVERY_N(1, INFO) << "This interval log will be logged with every thread, this one is from [Thread #" << threadId << "]";

  LOG_IF(strcmp(threadId, "2") == 0, INFO) << "This log is only for thread 2 and is ran by [Thread #" << threadId << "]";

  // Register 5 vague loggers
  for (int i = 1; i <= 5; ++i) {
     std::stringstream ss;
     ss << "logger" << i;
     el::Logger* logger = el::Loggers::getLogger(ss.str());
     LOG(INFO) << "Registered logger [" << *logger << "] [Thread #" << threadId << "]";
     CLOG(INFO, "default", "network") << "Triggering network log from default and network";
  }
  CLOG(INFO, "logger1") << "Logging using new logger [Thread #" << threadId << "]";
  CLOG(INFO, "no-logger") << "THIS SHOULD SAY LOGGER NOT REGISTERED YET [Thread #" << threadId << "]"; // << -- NOTE THIS!
  CLOG(INFO, "default", "network") << "Triggering network log from default and network";

  el::Logger* logger = el::Loggers::getLogger("default");
  logger->info("Info log from [Thread #%v]", threadId);

  // Check for log counters positions
  for (int i = 1; i <= 50; ++i) {
     LOG_EVERY_N(2, INFO) << "Counter pos: " << ELPP_COUNTER_POS << " [Thread #" << threadId << "]";
  }
  LOG_EVERY_N(2, INFO) << "Counter pos: " << ELPP_COUNTER_POS << " [Thread #" << threadId << "]";
  return NULL;
}

// If you wish you can define your own way to get thread ID
const char* getThreadId_CustomVersion(void) {
    return std::to_string(static_cast<long long>(pthread_self())).c_str();
}

int main(int argc, char** argv)
{
     _START_EASYLOGGINGPP(argc, argv);

     // Your thread ID specification
     el::CustomFormatSpecifier myThreadIdSpecifier("%mythreadId", getThreadId_CustomVersion);
     el::Helpers::installCustomFormatSpecifier(myThreadIdSpecifier);

     el::Loggers::addFlag(el::LoggingFlag::MultiLoggerSupport);

     // Note your %mythreadId or built-in, both are logged
     el::Loggers::reconfigureAllLoggers(el::ConfigurationType::Format, "%datetime %level (%thread | %mythreadId) [%logger] [%func] [%loc] %msg");
     el::Loggers::reconfigureAllLoggers(el::Level::Verbose, el::ConfigurationType::Format, "%datetime %level-%vlevel (%thread | %mythreadId) [%logger] [%func] [%loc] %msg");
     el::Loggers::getLogger("network");

     pthread_t thread1, thread2, thread3, thread4;

     // Create independent threads each of which will execute function
     pthread_create( &thread1, NULL, write, (void*)"1");
     pthread_create( &thread2, NULL, write, (void*)"2");
     pthread_create( &thread3, NULL, write, (void*)"3");

     el::Logger* logger = el::Loggers::getLogger("default");
     args.thrId = "4";
     args.logger = logger;
     pthread_create( &thread4, NULL, write2, (void*)&args);

     pthread_join(thread1, NULL);
     pthread_join(thread2, NULL);
     pthread_join(thread3, NULL);
     pthread_join(thread4, NULL);

    exit(0);
}
<|endoftext|>


<commit_before>#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;

int main( int argc, char** argv )
{
    Mat img(500, 500, CV_8UC3);
    RNG& rng = theRNG();

    for(;;)
    {
        int i, count = rng.uniform(1, 101);
        vector<Point> points;
        for( i = 0; i < count; i++ )
        {
            Point pt;
            pt.x = rng.uniform(img.cols/4, img.cols*3/4);
            pt.y = rng.uniform(img.rows/4, img.rows*3/4);

            points.push_back(pt);
        }

        RotatedRect box = minAreaRect(Mat(points));
        Point2f center, vtx[4];
        float radius = 0;
        minEnclosingCircle(Mat(points), center, radius);
        box.points(vtx);

        img = Scalar::all(0);
        for( i = 0; i < count; i++ )
            circle( img, points[i], 3, Scalar(0, 0, 255), CV_FILLED, CV_AA );

        for( i = 0; i < 4; i++ )
            line(img, vtx[i], vtx[(i+1)%4], Scalar(0, 255, 0), 1, CV_AA);

        circle(img, center, cvRound(radius), Scalar(0, 255, 255), 1, CV_AA);

        imshow( "rect & circle", img );

        char key = (char)cvWaitKey();
        if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
            break;
    }
    return 0;
}

<commit_msg>revamped<commit_after>#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;

void help()
{
	cout << "This program demonstrates finding the minimum enclosing box or circle of a set\n"
		"of points using functions: minAreaRect() minEnclosingCircle().\n"
		"Random points are generated and then enclosed.\n"
		"Call:\n"
		"./minarea\n"
   		"Using OpenCV version %s\n" << CV_VERSION << "\n" << endl;
}

int main( int argc, char** argv )
{
    Mat img(500, 500, CV_8UC3);
    RNG& rng = theRNG();
    help();
    for(;;)
    {
        int i, count = rng.uniform(1, 101);
        vector<Point> points;
        for( i = 0; i < count; i++ )
        {
            Point pt;
            pt.x = rng.uniform(img.cols/4, img.cols*3/4);
            pt.y = rng.uniform(img.rows/4, img.rows*3/4);

            points.push_back(pt);
        }

        RotatedRect box = minAreaRect(Mat(points));
        Point2f center, vtx[4];
        float radius = 0;
        minEnclosingCircle(Mat(points), center, radius);
        box.points(vtx);

        img = Scalar::all(0);
        for( i = 0; i < count; i++ )
            circle( img, points[i], 3, Scalar(0, 0, 255), CV_FILLED, CV_AA );

        for( i = 0; i < 4; i++ )
            line(img, vtx[i], vtx[(i+1)%4], Scalar(0, 255, 0), 1, CV_AA);

        circle(img, center, cvRound(radius), Scalar(0, 255, 255), 1, CV_AA);

        imshow( "rect & circle", img );

        char key = (char)cvWaitKey();
        if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
            break;
    }
    return 0;
}

<|endoftext|>


<commit_before>/*
 * IPAddress.cpp
 *
 * Copyright (C) 2006 by Universitaet Stuttgart (VIS). Alle Rechte vorbehalten.
 * Copyright (C) 2005 by Christoph Mueller (christoph.mueller@vis.uni-stuttgart.de). All rights reserved.
 */

#ifndef _WIN32
#include <arpa/inet.h>
#include <cstring>
#include <netdb.h>
#endif /* !_WIN32 */

#include "vislib/IPAddress.h"

#include "vislib/assert.h"
#include "vislib/IllegalParamException.h"
#include "vislib/NetworkInformation.h"
#include "vislib/OutOfRangeException.h"
#include "vislib/StringConverter.h"

/*
 * vislib::net::IPAddress::ALL_NODES_ON_LINK
 */
const vislib::net::IPAddress vislib::net::IPAddress::ALL_NODES_ON_LINK
#ifdef _WIN32
    (::in4addr_allnodesonlink);
#else /* _WIN32 */
    = vislib::net::IPAddress::Create("224.0.0.1");
#endif /* _WIN32 */

/*
 * vislib::net::IPAddress::ALL_ROUTERS_ON_LINK
 */
const vislib::net::IPAddress vislib::net::IPAddress::ALL_ROUTERS_ON_LINK
#ifdef _WIN32
    (::in4addr_allroutersonlink);
#else /* _WIN32 */
    = vislib::net::IPAddress::Create("224.0.0.2");
#endif /* _WIN32 */

/*
 * vislib::net::IPAddress::ANY
 */
const vislib::net::IPAddress vislib::net::IPAddress::ANY(
    static_cast<unsigned long>(INADDR_ANY));

/*
 * vislib::net::IPAddress::BROADCAST
 */
const  vislib::net::IPAddress vislib::net::IPAddress::BROADCAST(
    static_cast<unsigned long>(INADDR_BROADCAST));

/*
 * vislib::net::IPAddress::LOCALHOST
 */
const vislib::net::IPAddress vislib::net::IPAddress::LOCALHOST(
    static_cast<unsigned long>(INADDR_LOOPBACK));

/*
 * vislib::net::IPAddress::NONE
 */
const vislib::net::IPAddress vislib::net::IPAddress::NONE(
    static_cast<unsigned long>(INADDR_NONE));

/*
 * vislib::net::IPAddress::Create
 */
vislib::net::IPAddress vislib::net::IPAddress::Create(const char *address) {
    IPAddress retval;

    if (!retval.Lookup(address)) {
        throw IllegalParamException("address", __FILE__, __LINE__);
    }

    return retval;
}

/*
 * vislib::net::IPAddress::IPAddress
 */
vislib::net::IPAddress::IPAddress(const char *address) {
    VERIFY(this->Lookup(address));
}

/*
 * vislib::net::IPAddress::IPAddress
 */
vislib::net::IPAddress::IPAddress(unsigned char i1, unsigned char i2,
        unsigned char i3, unsigned char i4) {
#ifdef _WIN32
    this->address.S_un.S_un_b.s_b1 = i1;
    this->address.S_un.S_un_b.s_b2 = i2;
    this->address.S_un.S_un_b.s_b3 = i3;
    this->address.S_un.S_un_b.s_b4 = i4;
#else /* _WIN32 */
    this->address.s_addr
        = (static_cast<unsigned int>(i1))
        + (static_cast<unsigned int>(i2) << 8)
        + (static_cast<unsigned int>(i3) << 16)
        + (static_cast<unsigned int>(i4) << 24);
#endif /* _WIN32 */
}

/*
 * vislib::net::IPAddress::IPAddress
 */
vislib::net::IPAddress::IPAddress(const unsigned long address,
                                  const bool isHostByteOrder) {
    this->address.s_addr = isHostByteOrder ? htonl(address) : address;
}

/*
 * vislib::net::IPAddress::~IPAddress
 */
vislib::net::IPAddress::~IPAddress(void) {
}

/*
 * vislib::net::IPAddress::GetPrefix
 */
vislib::net::IPAddress vislib::net::IPAddress::GetPrefix(
        const ULONG prefixLength) const {
    IPAddress netmask = NetworkInformation::PrefixToNetmask4(prefixLength);
    return (netmask & *this);
}

/*
 * vislib::net::IPAddress::Lookup
 */
bool vislib::net::IPAddress::Lookup(const char *hostname) {

    /* Try to find the host by its name first. */
    hostent *host = ::gethostbyname(hostname);

    if (host != NULL) {
        /* Host found. */
        ::memcpy(&this->address.s_addr, host->h_addr_list[0], host->h_length);

    } else {
        /* Host not found, assume IP address. */

        if ((this->address.s_addr = ::inet_addr(hostname)) == INADDR_NONE) {
            /* IP address is invalid, return error. */
            return false;
        }
    }

    return true;
}

/*
 * vislib::net::IPAddress::ToStringA
 */
vislib::StringA vislib::net::IPAddress::ToStringA(void) const {
    StringA retval(::inet_ntoa(this->address));
    return retval;
}

/*
 * vislib::net::IPAddress::operator []
 */
BYTE vislib::net::IPAddress::operator [](const int i) const {
    if ((i > 0) && (i < static_cast<int>(sizeof(this->address)))) {
        return reinterpret_cast<const BYTE *>(&this->address)[i];
    } else {
        throw OutOfRangeException(i, 0, sizeof(this->address), __FILE__,
            __LINE__);
    }
}

/*
 * vislib::net::IPAddress::operator =
 */
vislib::net::IPAddress& vislib::net::IPAddress::operator =(const IPAddress& rhs) {
    if (this != &rhs) {
        ::memcpy(&this->address, &rhs.address, sizeof(in_addr));
    }

    return *this;
}

/*
 * vislib::net::IPAddress::operator ==
 */
bool vislib::net::IPAddress::operator ==(const IPAddress& rhs) const {
    return (::memcmp(&this->address, &rhs.address, sizeof(in_addr)) == 0);
}

/*
 * vislib::net::IPAddress::operator &=
 */
vislib::net::IPAddress& vislib::net::IPAddress::operator &=(
        const IPAddress& mask) {
#ifdef _WIN32
    this->address.S_un.S_addr &= mask.address.S_un.S_addr;
#else /* _WIN32 */
    this->address.s_addr &= mask.address.s_addr;
#endif /* _WIN32 */
    return *this;
}
<commit_msg>Fixed erroneous IP constants (how could that ever have worked?!)<commit_after>/*
 * IPAddress.cpp
 *
 * Copyright (C) 2006 by Universitaet Stuttgart (VIS). Alle Rechte vorbehalten.
 * Copyright (C) 2005 by Christoph Mueller (christoph.mueller@vis.uni-stuttgart.de). All rights reserved.
 */

#ifndef _WIN32
#include <arpa/inet.h>
#include <cstring>
#include <netdb.h>
#endif /* !_WIN32 */

#include "vislib/IPAddress.h"

#include "vislib/assert.h"
#include "vislib/IllegalParamException.h"
#include "vislib/NetworkInformation.h"
#include "vislib/OutOfRangeException.h"
#include "vislib/StringConverter.h"

/*
 * vislib::net::IPAddress::ALL_NODES_ON_LINK
 */
const vislib::net::IPAddress vislib::net::IPAddress::ALL_NODES_ON_LINK
#ifdef _WIN32
    (::in4addr_allnodesonlink);
#else /* _WIN32 */
    = vislib::net::IPAddress::Create("224.0.0.1");
#endif /* _WIN32 */

/*
 * vislib::net::IPAddress::ALL_ROUTERS_ON_LINK
 */
const vislib::net::IPAddress vislib::net::IPAddress::ALL_ROUTERS_ON_LINK
#ifdef _WIN32
    (::in4addr_allroutersonlink);
#else /* _WIN32 */
    = vislib::net::IPAddress::Create("224.0.0.2");
#endif /* _WIN32 */

/*
 * vislib::net::IPAddress::ANY
 */
const vislib::net::IPAddress vislib::net::IPAddress::ANY(
    static_cast<unsigned long>(INADDR_ANY), true);

/*
 * vislib::net::IPAddress::BROADCAST
 */
const  vislib::net::IPAddress vislib::net::IPAddress::BROADCAST(
    static_cast<unsigned long>(INADDR_BROADCAST), true);

/*
 * vislib::net::IPAddress::LOCALHOST
 */
const vislib::net::IPAddress vislib::net::IPAddress::LOCALHOST(
    static_cast<unsigned long>(INADDR_LOOPBACK), true);

/*
 * vislib::net::IPAddress::NONE
 */
const vislib::net::IPAddress vislib::net::IPAddress::NONE(
    static_cast<unsigned long>(INADDR_NONE), true);

/*
 * vislib::net::IPAddress::Create
 */
vislib::net::IPAddress vislib::net::IPAddress::Create(const char *address) {
    IPAddress retval;

    if (!retval.Lookup(address)) {
        throw IllegalParamException("address", __FILE__, __LINE__);
    }

    return retval;
}

/*
 * vislib::net::IPAddress::IPAddress
 */
vislib::net::IPAddress::IPAddress(const char *address) {
    VERIFY(this->Lookup(address));
}

/*
 * vislib::net::IPAddress::IPAddress
 */
vislib::net::IPAddress::IPAddress(unsigned char i1, unsigned char i2,
        unsigned char i3, unsigned char i4) {
#ifdef _WIN32
    this->address.S_un.S_un_b.s_b1 = i1;
    this->address.S_un.S_un_b.s_b2 = i2;
    this->address.S_un.S_un_b.s_b3 = i3;
    this->address.S_un.S_un_b.s_b4 = i4;
#else /* _WIN32 */
    this->address.s_addr
        = (static_cast<unsigned int>(i1))
        + (static_cast<unsigned int>(i2) << 8)
        + (static_cast<unsigned int>(i3) << 16)
        + (static_cast<unsigned int>(i4) << 24);
#endif /* _WIN32 */
}

/*
 * vislib::net::IPAddress::IPAddress
 */
vislib::net::IPAddress::IPAddress(const unsigned long address,
                                  const bool isHostByteOrder) {
    this->address.s_addr = isHostByteOrder ? htonl(address) : address;
}

/*
 * vislib::net::IPAddress::~IPAddress
 */
vislib::net::IPAddress::~IPAddress(void) {
}

/*
 * vislib::net::IPAddress::GetPrefix
 */
vislib::net::IPAddress vislib::net::IPAddress::GetPrefix(
        const ULONG prefixLength) const {
    IPAddress netmask = NetworkInformation::PrefixToNetmask4(prefixLength);
    return (netmask & *this);
}

/*
 * vislib::net::IPAddress::Lookup
 */
bool vislib::net::IPAddress::Lookup(const char *hostname) {

    /* Try to find the host by its name first. */
    hostent *host = ::gethostbyname(hostname);

    if (host != NULL) {
        /* Host found. */
        ::memcpy(&this->address.s_addr, host->h_addr_list[0], host->h_length);

    } else {
        /* Host not found, assume IP address. */

        if ((this->address.s_addr = ::inet_addr(hostname)) == INADDR_NONE) {
            /* IP address is invalid, return error. */
            return false;
        }
    }

    return true;
}

/*
 * vislib::net::IPAddress::ToStringA
 */
vislib::StringA vislib::net::IPAddress::ToStringA(void) const {
    StringA retval(::inet_ntoa(this->address));
    return retval;
}

/*
 * vislib::net::IPAddress::operator []
 */
BYTE vislib::net::IPAddress::operator [](const int i) const {
    if ((i > 0) && (i < static_cast<int>(sizeof(this->address)))) {
        return reinterpret_cast<const BYTE *>(&this->address)[i];
    } else {
        throw OutOfRangeException(i, 0, sizeof(this->address), __FILE__,
            __LINE__);
    }
}

/*
 * vislib::net::IPAddress::operator =
 */
vislib::net::IPAddress& vislib::net::IPAddress::operator =(const IPAddress& rhs) {
    if (this != &rhs) {
        ::memcpy(&this->address, &rhs.address, sizeof(in_addr));
    }

    return *this;
}

/*
 * vislib::net::IPAddress::operator ==
 */
bool vislib::net::IPAddress::operator ==(const IPAddress& rhs) const {
    return (::memcmp(&this->address, &rhs.address, sizeof(in_addr)) == 0);
}

/*
 * vislib::net::IPAddress::operator &=
 */
vislib::net::IPAddress& vislib::net::IPAddress::operator &=(
        const IPAddress& mask) {
#ifdef _WIN32
    this->address.S_un.S_addr &= mask.address.S_un.S_addr;
#else /* _WIN32 */
    this->address.s_addr &= mask.address.s_addr;
#endif /* _WIN32 */
    return *this;
}
<|endoftext|>


<commit_before>/*
Copyright 2013-present Barefoot Networks, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "crash.h"

#include <config.h>
#include <errno.h>
#if HAVE_EXECINFO_H
#include <execinfo.h>
#endif
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#if HAVE_UCONTEXT_H
#include <ucontext.h>
#endif
#include <unistd.h>
#include <iostream>
#include "exename.h"
#include "exceptions.h"
#include "hex.h"
#include "log.h"

static const char *signames[] = {
    "NONE", "HUP",  "INT",  "QUIT", "ILL",  "TRAP", "ABRT",   "BUS",  "FPE",   "KILL",
    "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM", "STKFLT", "CHLD", "CONT",  "STOP",
    "TSTP", "TTIN", "TTOU", "URG",  "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "POLL",
    "PWR",  "SYS"
};

#ifdef MULTITHREAD
#include <pthread.h>
#include <mutex>
std::vector<pthread_t>          thread_ids;
__thread        int             my_id;

void register_thread() {
    static std::mutex           lock;
    std::lock_guard<std::mutex> acquire(lock);
    my_id = thread_ids.size();
    thread_ids.push_back(pthread_self());
}
#define MTONLY(...)     __VA_ARGS__
#else
#define MTONLY(...)
#endif  // MULTITHREAD

static MTONLY(__thread) int shutdown_loop = 0;   // avoid infinite loop if shutdown crashes

static void sigint_shutdown(int sig, siginfo_t *, void *) {
    if (shutdown_loop++) _exit(-1);
    LOG1("Exiting with SIG" << signames[sig]);
    _exit(sig + 0x80);
}

/*
 * call external program addr2line WITHOUT using malloc or stdio or anything
 * else that might be problematic if there's memory corruption or exhaustion
 */
const char *addr2line(void *addr, const char *text) {
MTONLY(
    static std::mutex           lock;
    std::lock_guard<std::mutex> acquire(lock); )
    static pid_t child = 0;
    static int to_child, from_child;
    static char binary[PATH_MAX];
    static char buffer[PATH_MAX];
    const char *t;

    if (!text || !(t = strchr(text, '('))) {
        text = exename();
        t = text + strlen(text); }
    memcpy(buffer, text, t-text);
    buffer[t-text] = 0;
    if (child && strcmp(binary, buffer)) {
        child = 0;
        close(to_child);
        close(from_child); }
    memcpy(binary, buffer, (t-text) + 1);
    text = binary;
    if (!child) {
        int pfd1[2], pfd2[2];
        char *p = buffer;
        const char *argv[4] = { "/bin/sh", "-c", buffer, 0 };
        strcpy(p, "addr2line "); p += strlen(p);  // NOLINT
        strcpy(p, " -Cfspe "); p += strlen(p);    // NOLINT
        t = text + strlen(text);
        if (!memchr(text, '/', t-text)) {
            strcpy(p, "$(which "); p += strlen(p); }        // NOLINT
        memcpy(p, text, t-text);
        p += t-text;
        if (!memchr(text, '/', t-text)) *p++ = ')';
        *p = 0;
        child = -1;
#if HAVE_PIPE2
        if (pipe2(pfd1, O_CLOEXEC) < 0) return 0;
        if (pipe2(pfd2, O_CLOEXEC) < 0) return 0;
#else
        if (pipe(pfd1) < 0) return 0;
        if (pipe(pfd2) < 0) return 0;
        fcntl(pfd1[0], F_SETFD, FD_CLOEXEC | fcntl(pfd1[0], F_GETFL));
        fcntl(pfd1[1], F_SETFD, FD_CLOEXEC | fcntl(pfd1[1], F_GETFL));
        fcntl(pfd2[0], F_SETFD, FD_CLOEXEC | fcntl(pfd2[0], F_GETFL));
        fcntl(pfd2[1], F_SETFD, FD_CLOEXEC | fcntl(pfd2[1], F_GETFL));
#endif
        while ((child = fork()) == -1 && errno == EAGAIN) {}
        if (child == -1) return 0;
        if (child == 0) {
            dup2(pfd1[1], 1);
            dup2(pfd1[1], 2);
            dup2(pfd2[0], 0);
            execvp(argv[0], (char*const*)argv);
            _exit(-1); }
        close(pfd1[1]);
        from_child = pfd1[0];
        close(pfd2[0]);
        to_child = pfd2[1]; }
    if (child == -1) return 0;
    char *p = buffer;
    uintptr_t a = (uintptr_t)addr;
    int shift = (CHAR_BIT * sizeof(uintptr_t) - 1) & ~3;
    while (shift > 0 && (a >> shift) == 0) shift -= 4;
    while (shift >= 0) {
        *p++ = "0123456789abcdef"[(a >> shift) & 0xf];
        shift -= 4; }
    *p++ = '\n';
    auto _unused = write(to_child, buffer, p-buffer);
    (void)_unused;
    p = buffer;
    int len;
    while (p < buffer + sizeof(buffer) - 1 &&
           (len = read(from_child, p, buffer+sizeof(buffer)-p-1)) > 0 &&
           (p += len) && !memchr(p-len, '\n', len)) {}
    *p = 0;
    if ((p = strchr(buffer, '\n'))) *p = 0;
    if (buffer[0] == 0 || buffer[0] == '?')
        return 0;
    return buffer;
}

#if HAVE_UCONTEXT_H
static void dumpregs(mcontext_t *mctxt) {
#if defined(REG_EAX)
    LOG1(" eax=" << hex(mctxt->gregs[REG_EAX], 8, '0') <<
         " ebx=" << hex(mctxt->gregs[REG_EBX], 8, '0') <<
         " ecx=" << hex(mctxt->gregs[REG_ECX], 8, '0') <<
         " edx=" << hex(mctxt->gregs[REG_EDX], 8, '0'));
    LOG1(" edi=" << hex(mctxt->gregs[REG_EDI], 8, '0') <<
         " esi=" << hex(mctxt->gregs[REG_ESI], 8, '0') <<
         " ebp=" << hex(mctxt->gregs[REG_EBP], 8, '0') <<
         " esp=" << hex(mctxt->gregs[REG_ESP], 8, '0'));
#elif defined(REG_RAX)
    LOG1(" rax=" << hex(mctxt->gregs[REG_RAX], 16, '0') <<
         " rbx=" << hex(mctxt->gregs[REG_RBX], 16, '0') <<
         " rcx=" << hex(mctxt->gregs[REG_RCX], 16, '0'));
    LOG1(" rdx=" << hex(mctxt->gregs[REG_RDX], 16, '0') <<
         " rdi=" << hex(mctxt->gregs[REG_RDI], 16, '0') <<
         " rsi=" << hex(mctxt->gregs[REG_RSI], 16, '0'));
    LOG1(" rbp=" << hex(mctxt->gregs[REG_RBP], 16, '0') <<
         " rsp=" << hex(mctxt->gregs[REG_RSP], 16, '0') <<
         "  r8=" << hex(mctxt->gregs[REG_R8],  16, '0'));
    LOG1("  r9=" << hex(mctxt->gregs[REG_R9],  16, '0') <<
         " r10=" << hex(mctxt->gregs[REG_R10], 16, '0') <<
         " r11=" << hex(mctxt->gregs[REG_R11], 16, '0'));
    LOG1(" r12=" << hex(mctxt->gregs[REG_R12], 16, '0') <<
         " r13=" << hex(mctxt->gregs[REG_R13], 16, '0') <<
         " r14=" << hex(mctxt->gregs[REG_R14], 16, '0'));
    LOG1(" r15=" << hex(mctxt->gregs[REG_R15], 16, '0'));
#elif defined(__i386__)
    LOG1(" eax=" << hex(mctxt->mc_eax, 8, '0') <<
         " ebx=" << hex(mctxt->mc_ebx, 8, '0') <<
         " ecx=" << hex(mctxt->mc_ecx, 8, '0') <<
         " edx=" << hex(mctxt->mc_edx, 8, '0'));
    LOG1(" edi=" << hex(mctxt->mc_edi, 8, '0') <<
         " esi=" << hex(mctxt->mc_esi, 8, '0') <<
         " ebp=" << hex(mctxt->mc_ebp, 8, '0') <<
         " esp=" << hex(mctxt->mc_esp, 8, '0'));
#elif defined(__amd64__)
    LOG1(" rax=" << hex(mctxt->mc_rax, 16, '0') <<
         " rbx=" << hex(mctxt->mc_rbx, 16, '0') <<
         " rcx=" << hex(mctxt->mc_rcx, 16, '0'));
    LOG1(" rdx=" << hex(mctxt->mc_rdx, 16, '0') <<
         " rdi=" << hex(mctxt->mc_rdi, 16, '0') <<
         " rsi=" << hex(mctxt->mc_rsi, 16, '0'));
    LOG1(" rbp=" << hex(mctxt->mc_rbp, 16, '0') <<
         " rsp=" << hex(mctxt->mc_rsp, 16, '0') <<
         "  r8=" << hex(mctxt->mc_r8,  16, '0'));
    LOG1("  r9=" << hex(mctxt->mc_r9,  16, '0') <<
         " r10=" << hex(mctxt->mc_r10, 16, '0') <<
         " r11=" << hex(mctxt->mc_r11, 16, '0'));
    LOG1(" r12=" << hex(mctxt->mc_r12, 16, '0') <<
         " r13=" << hex(mctxt->mc_r13, 16, '0') <<
         " r14=" << hex(mctxt->mc_r14, 16, '0'));
    LOG1(" r15=" << hex(mctxt->mc_r15, 16, '0'));
#else
#warning "unknown machine type"
#endif
}
#endif

static void crash_shutdown(int sig, siginfo_t *info, void *uctxt) {
    if (shutdown_loop++) _exit(-1);
    MTONLY(
        static std::recursive_mutex lock;
        static int threads_dumped = 0;
        static bool killed_all_threads = false;
        lock.lock();
        if (!killed_all_threads) {
            killed_all_threads = true;
            for (int i = 0; i < int(thread_ids.size()); i++)
                if (i != my_id-1) {
                    pthread_kill(thread_ids[i], SIGABRT); } } )
    LOG1(MTONLY("Thread #" << my_id << " " <<) "exiting with SIG" <<
          signames[sig] << ", trace:");
    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
        sig == SIGBUS || sig == SIGTRAP)
        LOG1("  address = " << hex(info->si_addr));
#if HAVE_UCONTEXT_H
    dumpregs(&(static_cast<ucontext_t *>(uctxt)->uc_mcontext));
#else
    (void) uctxt;  // Suppress unused parameter warning.
#endif
#if HAVE_EXECINFO_H
    if (LOGGING(1)) {
        static void *buffer[64];
        int size = backtrace(buffer, 64);
        char **strings = backtrace_symbols(buffer, size);
        for (int i = 1; i < size; i++) {
            if (strings)
                LOG1("  " << strings[i]);
            if (const char *line = addr2line(buffer[i], strings ? strings[i] : 0))
                LOG1("    " << line); }
        if (size < 1)
            LOG1("backtrace failed");
        free(strings); }
#endif
    MTONLY(
        if (++threads_dumped < int(thread_ids.size())) {
            lock.unlock();
            pthread_exit(0);
        } else {
            lock.unlock(); } )
    if (sig != SIGABRT)
        BUG("Exiting with SIG%s", signames[sig]);
    _exit(sig + 0x80);
}

void setup_signals() {
    struct sigaction    sigact;
    sigact.sa_sigaction = sigint_shutdown;
    sigact.sa_flags = SA_SIGINFO;
    sigemptyset(&sigact.sa_mask);
    sigaction(SIGHUP, &sigact, 0);
    sigaction(SIGINT, &sigact, 0);
    sigaction(SIGQUIT, &sigact, 0);
    sigaction(SIGTERM, &sigact, 0);
    sigact.sa_sigaction = crash_shutdown;
    sigaction(SIGILL, &sigact, 0);
    sigaction(SIGABRT, &sigact, 0);
    sigaction(SIGFPE, &sigact, 0);
    sigaction(SIGSEGV, &sigact, 0);
    sigaction(SIGBUS, &sigact, 0);
    sigaction(SIGTRAP, &sigact, 0);
    signal(SIGPIPE, SIG_IGN);
}
<commit_msg>crash.cpp: Register names fixed for building under Cygwin. (#3296)<commit_after>/*
Copyright 2013-present Barefoot Networks, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "crash.h"

#include <config.h>
#include <errno.h>
#if HAVE_EXECINFO_H
#include <execinfo.h>
#endif
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#if HAVE_UCONTEXT_H
#include <ucontext.h>
#endif
#include <unistd.h>
#include <iostream>
#include "exename.h"
#include "exceptions.h"
#include "hex.h"
#include "log.h"

static const char *signames[] = {
    "NONE", "HUP",  "INT",  "QUIT", "ILL",  "TRAP", "ABRT",   "BUS",  "FPE",   "KILL",
    "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM", "STKFLT", "CHLD", "CONT",  "STOP",
    "TSTP", "TTIN", "TTOU", "URG",  "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "POLL",
    "PWR",  "SYS"
};

#ifdef MULTITHREAD
#include <pthread.h>
#include <mutex>
std::vector<pthread_t>          thread_ids;
__thread        int             my_id;

void register_thread() {
    static std::mutex           lock;
    std::lock_guard<std::mutex> acquire(lock);
    my_id = thread_ids.size();
    thread_ids.push_back(pthread_self());
}
#define MTONLY(...)     __VA_ARGS__
#else
#define MTONLY(...)
#endif  // MULTITHREAD

static MTONLY(__thread) int shutdown_loop = 0;   // avoid infinite loop if shutdown crashes

static void sigint_shutdown(int sig, siginfo_t *, void *) {
    if (shutdown_loop++) _exit(-1);
    LOG1("Exiting with SIG" << signames[sig]);
    _exit(sig + 0x80);
}

/*
 * call external program addr2line WITHOUT using malloc or stdio or anything
 * else that might be problematic if there's memory corruption or exhaustion
 */
const char *addr2line(void *addr, const char *text) {
MTONLY(
    static std::mutex           lock;
    std::lock_guard<std::mutex> acquire(lock); )
    static pid_t child = 0;
    static int to_child, from_child;
    static char binary[PATH_MAX];
    static char buffer[PATH_MAX];
    const char *t;

    if (!text || !(t = strchr(text, '('))) {
        text = exename();
        t = text + strlen(text); }
    memcpy(buffer, text, t-text);
    buffer[t-text] = 0;
    if (child && strcmp(binary, buffer)) {
        child = 0;
        close(to_child);
        close(from_child); }
    memcpy(binary, buffer, (t-text) + 1);
    text = binary;
    if (!child) {
        int pfd1[2], pfd2[2];
        char *p = buffer;
        const char *argv[4] = { "/bin/sh", "-c", buffer, 0 };
        strcpy(p, "addr2line "); p += strlen(p);  // NOLINT
        strcpy(p, " -Cfspe "); p += strlen(p);    // NOLINT
        t = text + strlen(text);
        if (!memchr(text, '/', t-text)) {
            strcpy(p, "$(which "); p += strlen(p); }        // NOLINT
        memcpy(p, text, t-text);
        p += t-text;
        if (!memchr(text, '/', t-text)) *p++ = ')';
        *p = 0;
        child = -1;
#if HAVE_PIPE2
        if (pipe2(pfd1, O_CLOEXEC) < 0) return 0;
        if (pipe2(pfd2, O_CLOEXEC) < 0) return 0;
#else
        if (pipe(pfd1) < 0) return 0;
        if (pipe(pfd2) < 0) return 0;
        fcntl(pfd1[0], F_SETFD, FD_CLOEXEC | fcntl(pfd1[0], F_GETFL));
        fcntl(pfd1[1], F_SETFD, FD_CLOEXEC | fcntl(pfd1[1], F_GETFL));
        fcntl(pfd2[0], F_SETFD, FD_CLOEXEC | fcntl(pfd2[0], F_GETFL));
        fcntl(pfd2[1], F_SETFD, FD_CLOEXEC | fcntl(pfd2[1], F_GETFL));
#endif
        while ((child = fork()) == -1 && errno == EAGAIN) {}
        if (child == -1) return 0;
        if (child == 0) {
            dup2(pfd1[1], 1);
            dup2(pfd1[1], 2);
            dup2(pfd2[0], 0);
            execvp(argv[0], (char*const*)argv);
            _exit(-1); }
        close(pfd1[1]);
        from_child = pfd1[0];
        close(pfd2[0]);
        to_child = pfd2[1]; }
    if (child == -1) return 0;
    char *p = buffer;
    uintptr_t a = (uintptr_t)addr;
    int shift = (CHAR_BIT * sizeof(uintptr_t) - 1) & ~3;
    while (shift > 0 && (a >> shift) == 0) shift -= 4;
    while (shift >= 0) {
        *p++ = "0123456789abcdef"[(a >> shift) & 0xf];
        shift -= 4; }
    *p++ = '\n';
    auto _unused = write(to_child, buffer, p-buffer);
    (void)_unused;
    p = buffer;
    int len;
    while (p < buffer + sizeof(buffer) - 1 &&
           (len = read(from_child, p, buffer+sizeof(buffer)-p-1)) > 0 &&
           (p += len) && !memchr(p-len, '\n', len)) {}
    *p = 0;
    if ((p = strchr(buffer, '\n'))) *p = 0;
    if (buffer[0] == 0 || buffer[0] == '?')
        return 0;
    return buffer;
}

#if HAVE_UCONTEXT_H

#if defined (__CYGWIN__)
    #define REGNAME(regname) regname
#else
    #define REGNAME(regname) mc_##regname
#endif

static void dumpregs(mcontext_t *mctxt) {
#if defined(REG_EAX)
    LOG1(" eax=" << hex(mctxt->gregs[REG_EAX], 8, '0') <<
         " ebx=" << hex(mctxt->gregs[REG_EBX], 8, '0') <<
         " ecx=" << hex(mctxt->gregs[REG_ECX], 8, '0') <<
         " edx=" << hex(mctxt->gregs[REG_EDX], 8, '0'));
    LOG1(" edi=" << hex(mctxt->gregs[REG_EDI], 8, '0') <<
         " esi=" << hex(mctxt->gregs[REG_ESI], 8, '0') <<
         " ebp=" << hex(mctxt->gregs[REG_EBP], 8, '0') <<
         " esp=" << hex(mctxt->gregs[REG_ESP], 8, '0'));
#elif defined(REG_RAX)
    LOG1(" rax=" << hex(mctxt->gregs[REG_RAX], 16, '0') <<
         " rbx=" << hex(mctxt->gregs[REG_RBX], 16, '0') <<
         " rcx=" << hex(mctxt->gregs[REG_RCX], 16, '0'));
    LOG1(" rdx=" << hex(mctxt->gregs[REG_RDX], 16, '0') <<
         " rdi=" << hex(mctxt->gregs[REG_RDI], 16, '0') <<
         " rsi=" << hex(mctxt->gregs[REG_RSI], 16, '0'));
    LOG1(" rbp=" << hex(mctxt->gregs[REG_RBP], 16, '0') <<
         " rsp=" << hex(mctxt->gregs[REG_RSP], 16, '0') <<
         "  r8=" << hex(mctxt->gregs[REG_R8],  16, '0'));
    LOG1("  r9=" << hex(mctxt->gregs[REG_R9],  16, '0') <<
         " r10=" << hex(mctxt->gregs[REG_R10], 16, '0') <<
         " r11=" << hex(mctxt->gregs[REG_R11], 16, '0'));
    LOG1(" r12=" << hex(mctxt->gregs[REG_R12], 16, '0') <<
         " r13=" << hex(mctxt->gregs[REG_R13], 16, '0') <<
         " r14=" << hex(mctxt->gregs[REG_R14], 16, '0'));
    LOG1(" r15=" << hex(mctxt->gregs[REG_R15], 16, '0'));
#elif defined(__i386__)
    LOG1(" eax=" << hex(mctxt->REGNAME(eax), 8, '0') <<
         " ebx=" << hex(mctxt->REGNAME(ebx), 8, '0') <<
         " ecx=" << hex(mctxt->REGNAME(ecx), 8, '0') <<
         " edx=" << hex(mctxt->REGNAME(edx), 8, '0'));
    LOG1(" edi=" << hex(mctxt->REGNAME(edi), 8, '0') <<
         " esi=" << hex(mctxt->REGNAME(esi), 8, '0') <<
         " ebp=" << hex(mctxt->REGNAME(ebp), 8, '0') <<
         " esp=" << hex(mctxt->REGNAME(esp), 8, '0'));
#elif defined(__amd64__)
    LOG1(" rax=" << hex(mctxt->REGNAME(rax), 16, '0') <<
         " rbx=" << hex(mctxt->REGNAME(rbx), 16, '0') <<
         " rcx=" << hex(mctxt->REGNAME(rcx), 16, '0'));
    LOG1(" rdx=" << hex(mctxt->REGNAME(rdx), 16, '0') <<
         " rdi=" << hex(mctxt->REGNAME(rdi), 16, '0') <<
         " rsi=" << hex(mctxt->REGNAME(rsi), 16, '0'));
    LOG1(" rbp=" << hex(mctxt->REGNAME(rbp), 16, '0') <<
         " rsp=" << hex(mctxt->REGNAME(rsp), 16, '0') <<
         "  r8=" << hex(mctxt->REGNAME(r8),  16, '0'));
    LOG1("  r9=" << hex(mctxt->REGNAME(r9),  16, '0') <<
         " r10=" << hex(mctxt->REGNAME(r10), 16, '0') <<
         " r11=" << hex(mctxt->REGNAME(r11), 16, '0'));
    LOG1(" r12=" << hex(mctxt->REGNAME(r12), 16, '0') <<
         " r13=" << hex(mctxt->REGNAME(r13), 16, '0') <<
         " r14=" << hex(mctxt->REGNAME(r14), 16, '0'));
    LOG1(" r15=" << hex(mctxt->REGNAME(r15), 16, '0'));
#else
#warning "unknown machine type"
#endif
}
#endif

static void crash_shutdown(int sig, siginfo_t *info, void *uctxt) {
    if (shutdown_loop++) _exit(-1);
    MTONLY(
        static std::recursive_mutex lock;
        static int threads_dumped = 0;
        static bool killed_all_threads = false;
        lock.lock();
        if (!killed_all_threads) {
            killed_all_threads = true;
            for (int i = 0; i < int(thread_ids.size()); i++)
                if (i != my_id-1) {
                    pthread_kill(thread_ids[i], SIGABRT); } } )
    LOG1(MTONLY("Thread #" << my_id << " " <<) "exiting with SIG" <<
          signames[sig] << ", trace:");
    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
        sig == SIGBUS || sig == SIGTRAP)
        LOG1("  address = " << hex(info->si_addr));
#if HAVE_UCONTEXT_H
    dumpregs(&(static_cast<ucontext_t *>(uctxt)->uc_mcontext));
#else
    (void) uctxt;  // Suppress unused parameter warning.
#endif
#if HAVE_EXECINFO_H
    if (LOGGING(1)) {
        static void *buffer[64];
        int size = backtrace(buffer, 64);
        char **strings = backtrace_symbols(buffer, size);
        for (int i = 1; i < size; i++) {
            if (strings)
                LOG1("  " << strings[i]);
            if (const char *line = addr2line(buffer[i], strings ? strings[i] : 0))
                LOG1("    " << line); }
        if (size < 1)
            LOG1("backtrace failed");
        free(strings); }
#endif
    MTONLY(
        if (++threads_dumped < int(thread_ids.size())) {
            lock.unlock();
            pthread_exit(0);
        } else {
            lock.unlock(); } )
    if (sig != SIGABRT)
        BUG("Exiting with SIG%s", signames[sig]);
    _exit(sig + 0x80);
}

void setup_signals() {
    struct sigaction    sigact;
    sigact.sa_sigaction = sigint_shutdown;
    sigact.sa_flags = SA_SIGINFO;
    sigemptyset(&sigact.sa_mask);
    sigaction(SIGHUP, &sigact, 0);
    sigaction(SIGINT, &sigact, 0);
    sigaction(SIGQUIT, &sigact, 0);
    sigaction(SIGTERM, &sigact, 0);
    sigact.sa_sigaction = crash_shutdown;
    sigaction(SIGILL, &sigact, 0);
    sigaction(SIGABRT, &sigact, 0);
    sigaction(SIGFPE, &sigact, 0);
    sigaction(SIGSEGV, &sigact, 0);
    sigaction(SIGBUS, &sigact, 0);
    sigaction(SIGTRAP, &sigact, 0);
    signal(SIGPIPE, SIG_IGN);
}
<|endoftext|>


<commit_before>#include "process.hpp"
#include <windows.h>
#include <cstring>
#include <TlHelp32.h>
#include <stdexcept>

namespace TinyProcessLib {

Process::Data::Data() noexcept : id(0), handle(NULL) {}

// Simple HANDLE wrapper to close it automatically from the destructor.
class Handle {
public:
  Handle() noexcept : handle(INVALID_HANDLE_VALUE) { }
  ~Handle() noexcept {
    close();
  }
  void close() noexcept {
    if (handle != INVALID_HANDLE_VALUE)
      CloseHandle(handle);
  }
  HANDLE detach() noexcept {
    HANDLE old_handle = handle;
    handle = INVALID_HANDLE_VALUE;
    return old_handle;
  }
  operator HANDLE() const noexcept { return handle; }
  HANDLE* operator&() noexcept { return &handle; }
private:
  HANDLE handle;
};

//Based on the discussion thread: https://www.reddit.com/r/cpp/comments/3vpjqg/a_new_platform_independent_process_library_for_c11/cxq1wsj
std::mutex create_process_mutex;

//Based on the example at https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx.
Process::id_type Process::open(const string_type &command, const string_type &path) noexcept {
  if(open_stdin)
    stdin_fd=std::unique_ptr<fd_type>(new fd_type(NULL));
  if(read_stdout)
    stdout_fd=std::unique_ptr<fd_type>(new fd_type(NULL));
  if(read_stderr)
    stderr_fd=std::unique_ptr<fd_type>(new fd_type(NULL));

  Handle stdin_rd_p;
  Handle stdin_wr_p;
  Handle stdout_rd_p;
  Handle stdout_wr_p;
  Handle stderr_rd_p;
  Handle stderr_wr_p;

  SECURITY_ATTRIBUTES security_attributes;

  security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  security_attributes.bInheritHandle = TRUE;
  security_attributes.lpSecurityDescriptor = nullptr;

  std::lock_guard<std::mutex> lock(create_process_mutex);
  if(stdin_fd) {
    if (!CreatePipe(&stdin_rd_p, &stdin_wr_p, &security_attributes, 0) ||
        !SetHandleInformation(stdin_wr_p, HANDLE_FLAG_INHERIT, 0))
      return 0;
  }
  if(stdout_fd) {
    if (!CreatePipe(&stdout_rd_p, &stdout_wr_p, &security_attributes, 0) ||
        !SetHandleInformation(stdout_rd_p, HANDLE_FLAG_INHERIT, 0)) {
      return 0;
    }
  }
  if(stderr_fd) {
    if (!CreatePipe(&stderr_rd_p, &stderr_wr_p, &security_attributes, 0) ||
        !SetHandleInformation(stderr_rd_p, HANDLE_FLAG_INHERIT, 0)) {
      return 0;
    }
  }

  PROCESS_INFORMATION process_info;
  STARTUPINFO startup_info;

  ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));

  ZeroMemory(&startup_info, sizeof(STARTUPINFO));
  startup_info.cb = sizeof(STARTUPINFO);
  startup_info.hStdInput = stdin_rd_p;
  startup_info.hStdOutput = stdout_wr_p;
  startup_info.hStdError = stderr_wr_p;
  if(stdin_fd || stdout_fd || stderr_fd)
    startup_info.dwFlags |= STARTF_USESTDHANDLES;

  string_type process_command=command;
#ifdef MSYS_PROCESS_USE_SH
  size_t pos=0;
  while((pos=process_command.find('\\', pos))!=string_type::npos) {
    process_command.replace(pos, 1, "\\\\\\\\");
    pos+=4;
  }
  pos=0;
  while((pos=process_command.find('\"', pos))!=string_type::npos) {
    process_command.replace(pos, 1, "\\\"");
    pos+=2;
  }
  process_command.insert(0, "sh -c \"");
  process_command+="\"";
#endif

  BOOL bSuccess = CreateProcess(nullptr, process_command.empty()?nullptr:&process_command[0], nullptr, nullptr, TRUE, 0,
                                nullptr, path.empty()?nullptr:path.c_str(), &startup_info, &process_info);

  if(!bSuccess) {
    CloseHandle(process_info.hProcess);
    CloseHandle(process_info.hThread);
    return 0;
  }
  else {
    CloseHandle(process_info.hThread);
  }

  if(stdin_fd) *stdin_fd=stdin_wr_p.detach();
  if(stdout_fd) *stdout_fd=stdout_rd_p.detach();
  if(stderr_fd) *stderr_fd=stderr_rd_p.detach();

  closed=false;
  data.id=process_info.dwProcessId;
  data.handle=process_info.hProcess;
  return process_info.dwProcessId;
}

void Process::async_read() noexcept {
  if(data.id==0)
    return;

  if(stdout_fd) {
    stdout_thread=std::thread([this](){
      DWORD n;
      std::unique_ptr<char[]> buffer(new char[buffer_size]);
      for (;;) {
        BOOL bSuccess = ReadFile(*stdout_fd, static_cast<CHAR*>(buffer.get()), static_cast<DWORD>(buffer_size), &n, nullptr);
        if(!bSuccess || n == 0)
          break;
        read_stdout(buffer.get(), static_cast<size_t>(n));
      }
    });
  }
  if(stderr_fd) {
    stderr_thread=std::thread([this](){
      DWORD n;
      std::unique_ptr<char[]> buffer(new char[buffer_size]);
      for (;;) {
        BOOL bSuccess = ReadFile(*stderr_fd, static_cast<CHAR*>(buffer.get()), static_cast<DWORD>(buffer_size), &n, nullptr);
        if(!bSuccess || n == 0)
          break;
        read_stderr(buffer.get(), static_cast<size_t>(n));
      }
    });
  }
}

int Process::get_exit_status() noexcept {
  if(data.id==0)
    return -1;

  DWORD exit_status;
  WaitForSingleObject(data.handle, INFINITE);
  if(!GetExitCodeProcess(data.handle, &exit_status))
    exit_status=-1;
  {
    std::lock_guard<std::mutex> lock(close_mutex);
    CloseHandle(data.handle);
    closed=true;
  }
  close_fds();

  return static_cast<int>(exit_status);
}

bool Process::try_get_exit_status(int &exit_status) noexcept {
  if(data.id==0)
    return false;

  DWORD wait_status = WaitForSingleObject(data.handle, 0);

  if (wait_status == WAIT_TIMEOUT)
    return false;

  DWORD exit_status_win;
  if(!GetExitCodeProcess(data.handle, &exit_status_win))
    exit_status_win=-1;
  {
    std::lock_guard<std::mutex> lock(close_mutex);
    CloseHandle(data.handle);
    closed=true;
  }
  close_fds();

  exit_status = static_cast<int>(exit_status_win);
  return true;
}

void Process::close_fds() noexcept {
  if(stdout_thread.joinable())
    stdout_thread.join();
  if(stderr_thread.joinable())
    stderr_thread.join();

  if(stdin_fd)
    close_stdin();
  if(stdout_fd) {
    if(*stdout_fd!=NULL) CloseHandle(*stdout_fd);
    stdout_fd.reset();
  }
  if(stderr_fd) {
    if(*stderr_fd!=NULL) CloseHandle(*stderr_fd);
    stderr_fd.reset();
  }
}

bool Process::write(const char *bytes, size_t n) {
  if(!open_stdin)
    throw std::invalid_argument("Can't write to an unopened stdin pipe. Please set open_stdin=true when constructing the process.");

  std::lock_guard<std::mutex> lock(stdin_mutex);
  if(stdin_fd) {
    DWORD written;
    BOOL bSuccess=WriteFile(*stdin_fd, bytes, static_cast<DWORD>(n), &written, nullptr);
    if(!bSuccess || written==0) {
      return false;
    }
    else {
      return true;
    }
  }
  return false;
}

void Process::close_stdin() noexcept {
  std::lock_guard<std::mutex> lock(stdin_mutex);
  if(stdin_fd) {
    if(*stdin_fd!=NULL) CloseHandle(*stdin_fd);
    stdin_fd.reset();
  }
}

//Based on http://stackoverflow.com/a/1173396
void Process::kill(bool /*force*/) noexcept {
  std::lock_guard<std::mutex> lock(close_mutex);
  if(data.id>0 && !closed) {
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if(snapshot) {
      PROCESSENTRY32 process;
      ZeroMemory(&process, sizeof(process));
      process.dwSize = sizeof(process);
      if(Process32First(snapshot, &process)) {
        do {
          if(process.th32ParentProcessID==data.id) {
            HANDLE process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, process.th32ProcessID);
            if(process_handle) {
              TerminateProcess(process_handle, 2);
              CloseHandle(process_handle);
            }
          }
        } while (Process32Next(snapshot, &process));
      }
      CloseHandle(snapshot);
    }
    TerminateProcess(data.handle, 2);
  }
}

//Based on http://stackoverflow.com/a/1173396
void Process::kill(id_type id, bool /*force*/) noexcept {
  if(id==0)
    return;

  HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if(snapshot) {
    PROCESSENTRY32 process;
    ZeroMemory(&process, sizeof(process));
    process.dwSize = sizeof(process);
    if(Process32First(snapshot, &process)) {
      do {
        if(process.th32ParentProcessID==id) {
          HANDLE process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, process.th32ProcessID);
          if(process_handle) {
            TerminateProcess(process_handle, 2);
            CloseHandle(process_handle);
          }
        }
      } while (Process32Next(snapshot, &process));
    }
    CloseHandle(snapshot);
  }
  HANDLE process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, id);
  if(process_handle) TerminateProcess(process_handle, 2);
}

} // TinyProsessLib
<commit_msg>Fixes #29: CloseHandle no longer called on invalid handles<commit_after>#include "process.hpp"
#include <windows.h>
#include <cstring>
#include <TlHelp32.h>
#include <stdexcept>

namespace TinyProcessLib {

Process::Data::Data() noexcept : id(0), handle(NULL) {}

// Simple HANDLE wrapper to close it automatically from the destructor.
class Handle {
public:
  Handle() noexcept : handle(INVALID_HANDLE_VALUE) { }
  ~Handle() noexcept {
    close();
  }
  void close() noexcept {
    if (handle != INVALID_HANDLE_VALUE)
      CloseHandle(handle);
  }
  HANDLE detach() noexcept {
    HANDLE old_handle = handle;
    handle = INVALID_HANDLE_VALUE;
    return old_handle;
  }
  operator HANDLE() const noexcept { return handle; }
  HANDLE* operator&() noexcept { return &handle; }
private:
  HANDLE handle;
};

//Based on the discussion thread: https://www.reddit.com/r/cpp/comments/3vpjqg/a_new_platform_independent_process_library_for_c11/cxq1wsj
std::mutex create_process_mutex;

//Based on the example at https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx.
Process::id_type Process::open(const string_type &command, const string_type &path) noexcept {
  if(open_stdin)
    stdin_fd=std::unique_ptr<fd_type>(new fd_type(NULL));
  if(read_stdout)
    stdout_fd=std::unique_ptr<fd_type>(new fd_type(NULL));
  if(read_stderr)
    stderr_fd=std::unique_ptr<fd_type>(new fd_type(NULL));

  Handle stdin_rd_p;
  Handle stdin_wr_p;
  Handle stdout_rd_p;
  Handle stdout_wr_p;
  Handle stderr_rd_p;
  Handle stderr_wr_p;

  SECURITY_ATTRIBUTES security_attributes;

  security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  security_attributes.bInheritHandle = TRUE;
  security_attributes.lpSecurityDescriptor = nullptr;

  std::lock_guard<std::mutex> lock(create_process_mutex);
  if(stdin_fd) {
    if (!CreatePipe(&stdin_rd_p, &stdin_wr_p, &security_attributes, 0) ||
        !SetHandleInformation(stdin_wr_p, HANDLE_FLAG_INHERIT, 0))
      return 0;
  }
  if(stdout_fd) {
    if (!CreatePipe(&stdout_rd_p, &stdout_wr_p, &security_attributes, 0) ||
        !SetHandleInformation(stdout_rd_p, HANDLE_FLAG_INHERIT, 0)) {
      return 0;
    }
  }
  if(stderr_fd) {
    if (!CreatePipe(&stderr_rd_p, &stderr_wr_p, &security_attributes, 0) ||
        !SetHandleInformation(stderr_rd_p, HANDLE_FLAG_INHERIT, 0)) {
      return 0;
    }
  }

  PROCESS_INFORMATION process_info;
  STARTUPINFO startup_info;

  ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));

  ZeroMemory(&startup_info, sizeof(STARTUPINFO));
  startup_info.cb = sizeof(STARTUPINFO);
  startup_info.hStdInput = stdin_rd_p;
  startup_info.hStdOutput = stdout_wr_p;
  startup_info.hStdError = stderr_wr_p;
  if(stdin_fd || stdout_fd || stderr_fd)
    startup_info.dwFlags |= STARTF_USESTDHANDLES;

  string_type process_command=command;
#ifdef MSYS_PROCESS_USE_SH
  size_t pos=0;
  while((pos=process_command.find('\\', pos))!=string_type::npos) {
    process_command.replace(pos, 1, "\\\\\\\\");
    pos+=4;
  }
  pos=0;
  while((pos=process_command.find('\"', pos))!=string_type::npos) {
    process_command.replace(pos, 1, "\\\"");
    pos+=2;
  }
  process_command.insert(0, "sh -c \"");
  process_command+="\"";
#endif

  BOOL bSuccess = CreateProcess(nullptr, process_command.empty()?nullptr:&process_command[0], nullptr, nullptr, TRUE, 0,
                                nullptr, path.empty()?nullptr:path.c_str(), &startup_info, &process_info);

  if(!bSuccess)
    return 0;
  else
    CloseHandle(process_info.hThread);

  if(stdin_fd) *stdin_fd=stdin_wr_p.detach();
  if(stdout_fd) *stdout_fd=stdout_rd_p.detach();
  if(stderr_fd) *stderr_fd=stderr_rd_p.detach();

  closed=false;
  data.id=process_info.dwProcessId;
  data.handle=process_info.hProcess;
  return process_info.dwProcessId;
}

void Process::async_read() noexcept {
  if(data.id==0)
    return;

  if(stdout_fd) {
    stdout_thread=std::thread([this](){
      DWORD n;
      std::unique_ptr<char[]> buffer(new char[buffer_size]);
      for (;;) {
        BOOL bSuccess = ReadFile(*stdout_fd, static_cast<CHAR*>(buffer.get()), static_cast<DWORD>(buffer_size), &n, nullptr);
        if(!bSuccess || n == 0)
          break;
        read_stdout(buffer.get(), static_cast<size_t>(n));
      }
    });
  }
  if(stderr_fd) {
    stderr_thread=std::thread([this](){
      DWORD n;
      std::unique_ptr<char[]> buffer(new char[buffer_size]);
      for (;;) {
        BOOL bSuccess = ReadFile(*stderr_fd, static_cast<CHAR*>(buffer.get()), static_cast<DWORD>(buffer_size), &n, nullptr);
        if(!bSuccess || n == 0)
          break;
        read_stderr(buffer.get(), static_cast<size_t>(n));
      }
    });
  }
}

int Process::get_exit_status() noexcept {
  if(data.id==0)
    return -1;

  DWORD exit_status;
  WaitForSingleObject(data.handle, INFINITE);
  if(!GetExitCodeProcess(data.handle, &exit_status))
    exit_status=-1;
  {
    std::lock_guard<std::mutex> lock(close_mutex);
    CloseHandle(data.handle);
    closed=true;
  }
  close_fds();

  return static_cast<int>(exit_status);
}

bool Process::try_get_exit_status(int &exit_status) noexcept {
  if(data.id==0)
    return false;

  DWORD wait_status = WaitForSingleObject(data.handle, 0);

  if (wait_status == WAIT_TIMEOUT)
    return false;

  DWORD exit_status_win;
  if(!GetExitCodeProcess(data.handle, &exit_status_win))
    exit_status_win=-1;
  {
    std::lock_guard<std::mutex> lock(close_mutex);
    CloseHandle(data.handle);
    closed=true;
  }
  close_fds();

  exit_status = static_cast<int>(exit_status_win);
  return true;
}

void Process::close_fds() noexcept {
  if(stdout_thread.joinable())
    stdout_thread.join();
  if(stderr_thread.joinable())
    stderr_thread.join();

  if(stdin_fd)
    close_stdin();
  if(stdout_fd) {
    if(*stdout_fd!=NULL) CloseHandle(*stdout_fd);
    stdout_fd.reset();
  }
  if(stderr_fd) {
    if(*stderr_fd!=NULL) CloseHandle(*stderr_fd);
    stderr_fd.reset();
  }
}

bool Process::write(const char *bytes, size_t n) {
  if(!open_stdin)
    throw std::invalid_argument("Can't write to an unopened stdin pipe. Please set open_stdin=true when constructing the process.");

  std::lock_guard<std::mutex> lock(stdin_mutex);
  if(stdin_fd) {
    DWORD written;
    BOOL bSuccess=WriteFile(*stdin_fd, bytes, static_cast<DWORD>(n), &written, nullptr);
    if(!bSuccess || written==0) {
      return false;
    }
    else {
      return true;
    }
  }
  return false;
}

void Process::close_stdin() noexcept {
  std::lock_guard<std::mutex> lock(stdin_mutex);
  if(stdin_fd) {
    if(*stdin_fd!=NULL) CloseHandle(*stdin_fd);
    stdin_fd.reset();
  }
}

//Based on http://stackoverflow.com/a/1173396
void Process::kill(bool /*force*/) noexcept {
  std::lock_guard<std::mutex> lock(close_mutex);
  if(data.id>0 && !closed) {
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if(snapshot) {
      PROCESSENTRY32 process;
      ZeroMemory(&process, sizeof(process));
      process.dwSize = sizeof(process);
      if(Process32First(snapshot, &process)) {
        do {
          if(process.th32ParentProcessID==data.id) {
            HANDLE process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, process.th32ProcessID);
            if(process_handle) {
              TerminateProcess(process_handle, 2);
              CloseHandle(process_handle);
            }
          }
        } while (Process32Next(snapshot, &process));
      }
      CloseHandle(snapshot);
    }
    TerminateProcess(data.handle, 2);
  }
}

//Based on http://stackoverflow.com/a/1173396
void Process::kill(id_type id, bool /*force*/) noexcept {
  if(id==0)
    return;

  HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if(snapshot) {
    PROCESSENTRY32 process;
    ZeroMemory(&process, sizeof(process));
    process.dwSize = sizeof(process);
    if(Process32First(snapshot, &process)) {
      do {
        if(process.th32ParentProcessID==id) {
          HANDLE process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, process.th32ProcessID);
          if(process_handle) {
            TerminateProcess(process_handle, 2);
            CloseHandle(process_handle);
          }
        }
      } while (Process32Next(snapshot, &process));
    }
    CloseHandle(snapshot);
  }
  HANDLE process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, id);
  if(process_handle) TerminateProcess(process_handle, 2);
}

} // TinyProsessLib
<|endoftext|>


<commit_before>//===- IListIterator.cpp --------------------------------------------------===//
//
//                            The Bold Project
//
//  This file is distributed under the New BSD License.
//  See LICENSE for details.
//
//===----------------------------------------------------------------------===//
#include <bold/ADT/IListIterator.h>
#include <cassert>

using namespace bold;

//===----------------------------------------------------------------------===//
// IListIteratorBase
//===----------------------------------------------------------------------===//
IListIteratorBase::IListIteratorBase()
  : m_pNodePtr(NULL) {
}

IListIteratorBase::IListIteratorBase(NodeBase* pNode)
  : m_pNodePtr(pNode) {
}

void IListIteratorBase::advance()
{
  assert(NULL != m_pNodePtr && "trivial iterator can not advance");
  m_pNodePtr = m_pNodePtr->getNext();
}

void IListIteratorBase::retreat()
{
  assert(NULL != m_pNodePtr && "trivial iterator can not retreat");
  m_pNodePtr = m_pNodePtr->getPrev();
}
<commit_msg>Use IListNodeBase instead of type redefinition.<commit_after>//===- IListIterator.cpp --------------------------------------------------===//
//
//                            The Bold Project
//
//  This file is distributed under the New BSD License.
//  See LICENSE for details.
//
//===----------------------------------------------------------------------===//
#include <bold/ADT/IListIterator.h>
#include <cassert>

using namespace bold;

//===----------------------------------------------------------------------===//
// IListIteratorBase
//===----------------------------------------------------------------------===//
IListIteratorBase::IListIteratorBase()
  : m_pNodePtr(NULL) {
}

IListIteratorBase::IListIteratorBase(IListNodeBase* pNode)
  : m_pNodePtr(pNode) {
}

void IListIteratorBase::advance()
{
  assert(NULL != m_pNodePtr && "trivial iterator can not advance");
  m_pNodePtr = m_pNodePtr->getNext();
}

void IListIteratorBase::retreat()
{
  assert(NULL != m_pNodePtr && "trivial iterator can not retreat");
  m_pNodePtr = m_pNodePtr->getPrev();
}
<|endoftext|>


<commit_before>//===--- USRGeneration.cpp - Routines for USR generation ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/AST/ASTContext.h"
#include "swift/AST/Module.h"
#include "swift/AST/USRGeneration.h"
#include "swift/AST/Mangle.h"
#include "swift/AST/ASTMangler.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"

using namespace swift;
using namespace ide;

static inline StringRef getUSRSpacePrefix() {
  return "s:";
}

bool ide::printTypeUSR(Type Ty, raw_ostream &OS) {
  assert(!Ty->hasArchetype() && "cannot have contextless archetypes mangled.");
  OS << NewMangling::mangleTypeForDebugger(Ty->getRValueType(), nullptr);
  return false;
}

bool ide::printDeclTypeUSR(const ValueDecl *D, raw_ostream &OS) {
  using namespace Mangle;
  Mangler Mangler(true);
  Mangler.mangleDeclTypeForDebugger(D);
  Mangler.finalize(OS);
  return false;
}

bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) {
  using namespace Mangle;

  if (!isa<FuncDecl>(D) && !D->hasName())
    return true; // Ignore.
  if (D->getModuleContext()->isBuiltinModule())
    return true; // Ignore.

  ValueDecl *VD = const_cast<ValueDecl *>(D);

  auto interpretAsClangNode = [](const ValueDecl *D)->ClangNode {
    ClangNode ClangN = D->getClangNode();
    if (auto ClangD = ClangN.getAsDecl()) {
      // NSErrorDomain causes the clang enum to be imported like this:
      //
      // struct MyError {
      //     enum Code : Int32 {
      //         case errFirst
      //         case errSecond
      //     }
      //     static var errFirst: MyError.Code { get }
      //     static var errSecond: MyError.Code { get }
      // }
      //
      // The clang enum and enum constants are associated with both the
      // struct/nested enum, and the static vars/enum cases.
      // But we want unique USRs for the above symbols, so use the clang USR
      // for the enum and enum cases, and the Swift USR for the struct and vars.
      //
      if (isa<clang::EnumDecl>(ClangD)) {
        if (ClangD->hasAttr<clang::NSErrorDomainAttr>() && isa<StructDecl>(D))
          return ClangNode();
      } else if (auto *ClangEnumConst = dyn_cast<clang::EnumConstantDecl>(ClangD)) {
        if (auto *ClangEnum = dyn_cast<clang::EnumDecl>(ClangEnumConst->getDeclContext())) {
          if (ClangEnum->hasAttr<clang::NSErrorDomainAttr>() && isa<VarDecl>(D))
            return ClangNode();
        }
      }
    }
    return ClangN;
  };

  if (ClangNode ClangN = interpretAsClangNode(D)) {
    llvm::SmallString<128> Buf;
    if (auto ClangD = ClangN.getAsDecl()) {
      bool Ignore = clang::index::generateUSRForDecl(ClangD, Buf);
      if (!Ignore)
        OS << Buf.str();
      return Ignore;
    }

    auto &Importer = *D->getASTContext().getClangModuleLoader();

    auto ClangMacroInfo = ClangN.getAsMacro();
    auto PPRecord = Importer.getClangPreprocessor().getPreprocessingRecord();
    assert(PPRecord && "Clang importer should be created with "
                       "-detailed-preprocessing-record option");
    auto ClangMacroDef = PPRecord->findMacroDefinition(ClangMacroInfo);

    bool Ignore = clang::index::generateUSRForMacro(
        ClangMacroDef, Importer.getClangASTContext().getSourceManager(), Buf);
    if (!Ignore)
      OS << Buf.str();
    return Ignore;
  }

  if (!D->hasInterfaceType())
    return true;

  // FIXME: mangling 'self' in destructors crashes in mangler.
  if (isa<ParamDecl>(VD) && isa<DestructorDecl>(VD->getDeclContext()))
    return true;

  std::string Old = getUSRSpacePrefix().str();
  Mangler Mangler;

  Mangler.bindGenericParameters(VD->getDeclContext());

  if (auto Ctor = dyn_cast<ConstructorDecl>(VD)) {
    Mangler.mangleConstructorEntity(Ctor, /*isAllocating=*/false,
                                    /*uncurryingLevel=*/0);
  } else if (auto Dtor = dyn_cast<DestructorDecl>(VD)) {
    Mangler.mangleDestructorEntity(Dtor, /*isDeallocating=*/false);
  } else if (auto NTD = dyn_cast<NominalTypeDecl>(VD)) {
    Mangler.mangleNominalType(NTD);
  } else if (isa<TypeAliasDecl>(VD) || isa<AssociatedTypeDecl>(VD)) {
    Mangler.mangleContextOf(VD);
    Mangler.mangleDeclName(VD);
  } else {
    Mangler.mangleEntity(VD, /*uncurryingLevel=*/0);
  }

  Old += Mangler.finalize();

  NewMangling::ASTMangler NewMangler;
  std::string New = NewMangler.mangleDeclAsUSR(VD, getUSRSpacePrefix());

  OS << NewMangling::selectMangling(Old, New);

  return false;
}

bool ide::printAccessorUSR(const AbstractStorageDecl *D, AccessorKind AccKind,
                           llvm::raw_ostream &OS) {
  using namespace Mangle;

  // AccKind should always be either IsGetter or IsSetter here, based
  // on whether a reference is a mutating or non-mutating use.  USRs
  // aren't supposed to reflect implementation differences like stored
  // vs. addressed vs. observing.
  //
  // On the other side, the implementation indexer should be
  // registering the getter/setter USRs independently of how they're
  // actually implemented.  So a stored variable should still have
  // getter/setter USRs (pointing to the variable declaration), and an
  // addressed variable should have its "getter" point at the
  // addressor.

  AbstractStorageDecl *SD = const_cast<AbstractStorageDecl*>(D);
  std::string Old = getUSRSpacePrefix().str();
  Mangler Mangler;
  Mangler.mangleAccessorEntity(AccKind, AddressorKind::NotAddressor, SD);
  Old += Mangler.finalize();

  NewMangling::ASTMangler NewMangler;
  std::string New = NewMangler.mangleAccessorEntityAsUSR(AccKind,
                          AddressorKind::NotAddressor, SD, getUSRSpacePrefix());

  OS << NewMangling::selectMangling(Old, New);

  return false;
}

bool ide::printExtensionUSR(const ExtensionDecl *ED, raw_ostream &OS) {
  if (ED->getExtendedType().isNull())
    return true;

  // We make up a unique usr for each extension by combining a prefix
  // and the USR of the first value member of the extension.
  for (auto D : ED->getMembers()) {
    if (auto VD = dyn_cast<ValueDecl>(D)) {
      OS << getUSRSpacePrefix() << "e:";
      return printDeclUSR(VD, OS);
    }
  }
  if (ED->getExtendedType() && ED->getExtendedType()->getAnyNominal()) {
    OS << getUSRSpacePrefix() << "e:";
    printDeclUSR(ED->getExtendedType()->getAnyNominal(), OS);
  } else {
    return true;
  }
  for (auto Inherit : ED->getInherited()) {
    if (auto T = Inherit.getType()) {
      if (T->getAnyNominal())
        return printDeclUSR(T->getAnyNominal(), OS);
    }
  }
  return true;
}

<commit_msg>[USRGeneration] For clang macro USRs, use the more general API that doesn't require a PreprocessingRecord.<commit_after>//===--- USRGeneration.cpp - Routines for USR generation ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/AST/ASTContext.h"
#include "swift/AST/Module.h"
#include "swift/AST/USRGeneration.h"
#include "swift/AST/Mangle.h"
#include "swift/AST/ASTMangler.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"

using namespace swift;
using namespace ide;

static inline StringRef getUSRSpacePrefix() {
  return "s:";
}

bool ide::printTypeUSR(Type Ty, raw_ostream &OS) {
  assert(!Ty->hasArchetype() && "cannot have contextless archetypes mangled.");
  OS << NewMangling::mangleTypeForDebugger(Ty->getRValueType(), nullptr);
  return false;
}

bool ide::printDeclTypeUSR(const ValueDecl *D, raw_ostream &OS) {
  using namespace Mangle;
  Mangler Mangler(true);
  Mangler.mangleDeclTypeForDebugger(D);
  Mangler.finalize(OS);
  return false;
}

bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) {
  using namespace Mangle;

  if (!isa<FuncDecl>(D) && !D->hasName())
    return true; // Ignore.
  if (D->getModuleContext()->isBuiltinModule())
    return true; // Ignore.

  ValueDecl *VD = const_cast<ValueDecl *>(D);

  auto interpretAsClangNode = [](const ValueDecl *D)->ClangNode {
    ClangNode ClangN = D->getClangNode();
    if (auto ClangD = ClangN.getAsDecl()) {
      // NSErrorDomain causes the clang enum to be imported like this:
      //
      // struct MyError {
      //     enum Code : Int32 {
      //         case errFirst
      //         case errSecond
      //     }
      //     static var errFirst: MyError.Code { get }
      //     static var errSecond: MyError.Code { get }
      // }
      //
      // The clang enum and enum constants are associated with both the
      // struct/nested enum, and the static vars/enum cases.
      // But we want unique USRs for the above symbols, so use the clang USR
      // for the enum and enum cases, and the Swift USR for the struct and vars.
      //
      if (isa<clang::EnumDecl>(ClangD)) {
        if (ClangD->hasAttr<clang::NSErrorDomainAttr>() && isa<StructDecl>(D))
          return ClangNode();
      } else if (auto *ClangEnumConst = dyn_cast<clang::EnumConstantDecl>(ClangD)) {
        if (auto *ClangEnum = dyn_cast<clang::EnumDecl>(ClangEnumConst->getDeclContext())) {
          if (ClangEnum->hasAttr<clang::NSErrorDomainAttr>() && isa<VarDecl>(D))
            return ClangNode();
        }
      }
    }
    return ClangN;
  };

  if (ClangNode ClangN = interpretAsClangNode(D)) {
    llvm::SmallString<128> Buf;
    if (auto ClangD = ClangN.getAsDecl()) {
      bool Ignore = clang::index::generateUSRForDecl(ClangD, Buf);
      if (!Ignore)
        OS << Buf.str();
      return Ignore;
    }

    auto &Importer = *D->getASTContext().getClangModuleLoader();

    auto ClangMacroInfo = ClangN.getAsMacro();
    bool Ignore = clang::index::generateUSRForMacro(D->getNameStr(),
        ClangMacroInfo->getDefinitionLoc(),
        Importer.getClangASTContext().getSourceManager(), Buf);
    if (!Ignore)
      OS << Buf.str();
    return Ignore;
  }

  if (!D->hasInterfaceType())
    return true;

  // FIXME: mangling 'self' in destructors crashes in mangler.
  if (isa<ParamDecl>(VD) && isa<DestructorDecl>(VD->getDeclContext()))
    return true;

  std::string Old = getUSRSpacePrefix().str();
  Mangler Mangler;

  Mangler.bindGenericParameters(VD->getDeclContext());

  if (auto Ctor = dyn_cast<ConstructorDecl>(VD)) {
    Mangler.mangleConstructorEntity(Ctor, /*isAllocating=*/false,
                                    /*uncurryingLevel=*/0);
  } else if (auto Dtor = dyn_cast<DestructorDecl>(VD)) {
    Mangler.mangleDestructorEntity(Dtor, /*isDeallocating=*/false);
  } else if (auto NTD = dyn_cast<NominalTypeDecl>(VD)) {
    Mangler.mangleNominalType(NTD);
  } else if (isa<TypeAliasDecl>(VD) || isa<AssociatedTypeDecl>(VD)) {
    Mangler.mangleContextOf(VD);
    Mangler.mangleDeclName(VD);
  } else {
    Mangler.mangleEntity(VD, /*uncurryingLevel=*/0);
  }

  Old += Mangler.finalize();

  NewMangling::ASTMangler NewMangler;
  std::string New = NewMangler.mangleDeclAsUSR(VD, getUSRSpacePrefix());

  OS << NewMangling::selectMangling(Old, New);

  return false;
}

bool ide::printAccessorUSR(const AbstractStorageDecl *D, AccessorKind AccKind,
                           llvm::raw_ostream &OS) {
  using namespace Mangle;

  // AccKind should always be either IsGetter or IsSetter here, based
  // on whether a reference is a mutating or non-mutating use.  USRs
  // aren't supposed to reflect implementation differences like stored
  // vs. addressed vs. observing.
  //
  // On the other side, the implementation indexer should be
  // registering the getter/setter USRs independently of how they're
  // actually implemented.  So a stored variable should still have
  // getter/setter USRs (pointing to the variable declaration), and an
  // addressed variable should have its "getter" point at the
  // addressor.

  AbstractStorageDecl *SD = const_cast<AbstractStorageDecl*>(D);
  std::string Old = getUSRSpacePrefix().str();
  Mangler Mangler;
  Mangler.mangleAccessorEntity(AccKind, AddressorKind::NotAddressor, SD);
  Old += Mangler.finalize();

  NewMangling::ASTMangler NewMangler;
  std::string New = NewMangler.mangleAccessorEntityAsUSR(AccKind,
                          AddressorKind::NotAddressor, SD, getUSRSpacePrefix());

  OS << NewMangling::selectMangling(Old, New);

  return false;
}

bool ide::printExtensionUSR(const ExtensionDecl *ED, raw_ostream &OS) {
  if (ED->getExtendedType().isNull())
    return true;

  // We make up a unique usr for each extension by combining a prefix
  // and the USR of the first value member of the extension.
  for (auto D : ED->getMembers()) {
    if (auto VD = dyn_cast<ValueDecl>(D)) {
      OS << getUSRSpacePrefix() << "e:";
      return printDeclUSR(VD, OS);
    }
  }
  if (ED->getExtendedType() && ED->getExtendedType()->getAnyNominal()) {
    OS << getUSRSpacePrefix() << "e:";
    printDeclUSR(ED->getExtendedType()->getAnyNominal(), OS);
  } else {
    return true;
  }
  for (auto Inherit : ED->getInherited()) {
    if (auto T = Inherit.getType()) {
      if (T->getAnyNominal())
        return printDeclUSR(T->getAnyNominal(), OS);
    }
  }
  return true;
}

<|endoftext|>